javascript的webstorage数据存储问题,不能直接存undefined

news2024/12/24 8:24:17

这篇文章分享一下自己使用sessionStorage遇到的一个小问题,以后遇到要避坑。

需求是easyui表格的单元格编辑,点击保存的时候会结束当前行的编辑,然后修改editingId(当前编辑行记录的ID)。

目录

一、待解决问题

二、完整的页面代码

三、具体业务逻辑

添加数据

保存数据

编辑数据

四、问题分析

五、问题解决


一、待解决问题

如图,点击修改按钮时无响应,也没有报错。

二、完整的页面代码

menu_list.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<link rel="stylesheet" href="/css/themes/icon.css"/>
		<link rel="stylesheet" href="/css/themes/default/easyui.css" />
		<title>系统管理>>菜单列表</title>
		<script src="/js/public/jquery.min.js"></script>
		<script src="/js/easyui/jquery.easyui.min.js"></script>
		<script src="/js/easyui/easyui-lang-zh_CN.js"></script>
		<script src="/js/public/util.js"></script>
		<script src="/js/public/public.js"></script>
		<script src="/js/public/sessionStorage.js"></script>
		<script src="/js/menu_list.js"></script>
	</head>
	
	<body>
		<div>
			<a href="javascript:" class="easyui-linkbutton" onclick="insert()">添加</a>
			<a href="javascript:" class="easyui-linkbutton" onclick="edit()">修改</a>
			<a href="javascript:" class="easyui-linkbutton" onclick="save()">保存</a>
			<a href="javascript:" class="easyui-linkbutton" onclick="cancel()">取消</a>
			<a href="javascript:" class="easyui-linkbutton" onclick="expandAll()">展开全部</a>
			<a href="javascript:" class="easyui-linkbutton" onclick="collapseAll()">折叠全部</a>
		</div>

		<div id="mm" class="easyui-menu" style="width:120px;">
			<div onclick="append()" data-options="iconCls:'icon-add'">添加</div>
			<div onclick="removeIt()" data-options="iconCls:'icon-remove'">删除</div>
			<div class="menu-sep"></div>
			<div onclick="collapse()">折叠</div>
			<div onclick="expand()">展开</div>
		</div>
	
		<table id="menu_treegrid"></table>
	</body>
</html>

menu_list.js

let parentId;
let data = {
	id: "",
	name: "xxx",
	url: "",
	icon: "icon-xxx"
};

/**
 * 添加
 */
function insert() {
	let menuId = new Date().getTime();
	let treegrid = $("#menu_treegrid");

	treegrid.treegrid("append",{
		data: [{
			id: menuId,
			name: "xxx",
			url: "/html/xxx",
			icon: "icon-xxx"
		}]
	});

	// 保存editingId到sessionStorage
	storage("editingId", menuId);
	
	// 开启行编辑
	treegrid.treegrid("beginEdit", menuId);
}

/**
 * 修改
 */
function edit() {
	let editingId = getStorage("editingId");

	console.log(editingId);

	if (editingId) {
		$("#menu_treegrid").treegrid("select", editingId);
	} else {
		let row = $("#menu_treegrid").treegrid("getSelected");

		console.log("开始编辑行:");
		console.log(row);

		if (row) {
			storage("editingId", row.id);

			$("#menu_treegrid").treegrid("beginEdit", row.id);
		}
	}
}

/**
 * 保存
 */
function save() {
	let editingId = getStorage("editingId");

	if (editingId) {
		let treegrid = $("#menu_treegrid");

		if (editingId) {
			// 只有结束编辑才能获取到最新的值
			treegrid.treegrid("endEdit", editingId);

			let postData = {
				id: editingId,
				name: data.name,
				url: data.url,
				icon: data.icon,
				parentId: parentId
			};

			console.log(postData);
			storage("editingId", undefined);

			// post("/menu/updateById", postData, function () {
			// 	storage("editingId", undefined);
			// }, error);
		}
	}
}

/**
 * 取消
 */
function cancel() {
	let editingId = getStorage("editingId");

	if (editingId) {
		$("#menu_treegrid").treegrid("cancelEdit", editingId);

		storage("editingId", undefined);
	}
}

/**
 * 折叠全部
 */
function collapseAll() {
	$("#menu_treegrid").treegrid("collapseAll");
}

/**
 * 展开全部
 */
function expandAll() {
	$("#menu_treegrid").treegrid("expandAll");
}

/**
 * 添加
 */
function append() {
	let menuId = new Date().getTime();
	let treegrid = $("#menu_treegrid");
	let node = treegrid.treegrid("getSelected");

	parentId = node.id;
	storage("editingId", menuId);

	treegrid.treegrid("append",{
		parent: node.id,
		data: [{
			id: menuId,
			name: "xxx",
			url: "",
			icon: "icon-xxx"
		}]
	});

	let editingId = getStorage("editingId");

	treegrid.treegrid("beginEdit", editingId);
}

/**
 * 删除
 */
function removeIt() {
	let node = $("#menu_treegrid").treegrid("getSelected");

	if (node) {
		$("#menu_treegrid").treegrid("remove", node.id);
	}
}

/**
 * 折叠
 */
function collapse() {
	let node = $("#menu_treegrid").treegrid("getSelected");

	if (node) {
		$("#menu_treegrid").treegrid("collapse", node.id);
	}
}

/**
 * 展开
 */
function expand() {
	let node = $("#menu_treegrid").treegrid("getSelected");
	
	if (node) {
		$("#menu_treegrid").treegrid("expand", node.id);
	}
}

$(document).ready(function() {
	$("#menu_treegrid").treegrid({
		url: "/menu/listTreeGrid",
		method: "get",
		idField: "id",
		treeField: "name",
		fitColumns: true,
		pagination: true,
		pageSize: 10,
		pageList: [10, 20, 50, 100],
		columns:[[
			{title: "菜单编号", field: "id", hidden: true},
			{title: "菜单名称", field: "name", align: "left", editor: "textbox", width: 100},
			{title: "图标样式", field: "icon", align: "left", editor: "textbox", width: 100},
			{title: "页面地址", field: "url", align: "left", editor: "textbox", width: 200,
				formatter: function(value) {
					if (value) {
						return "<a href='" + value + "'>" + value + "</a>";
					} else {
						return "<div>/</div>";
					}
				}
			}
		]],
		onAfterEdit: function (row, changes) {
			console.log(changes);

			data = {
				id: row.id,
				name: row.name ? row.name : changes.name,
				url: row.url ? row.url : changes.url,
				icon: row.icon ? row.icon : changes.icon
			};;
		},
		onContextMenu: function (e, row) {
			e.preventDefault();

			$(this).treegrid("select", row.id);

			$("#mm").menu("show",{
				left: e.pageX,
				top: e.pageY
			});
		}
	}).treegrid("clientPaging");

});

(function($) {
	function pagerFilter(data) {
		if ($.isArray(data)) {    // is array
			data = {
				total: data.length,
				rows: data
			}
		}

		let dg = $(this);
		let state = dg.data("treegrid");
		let opts = dg.treegrid("options");
		let pager = dg.treegrid("getPager");

		pager.pagination({
			onSelectPage:function(pageNum, pageSize) {
				opts.pageNumber = pageNum;
				opts.pageSize = pageSize;

				pager.pagination("refresh",{
					pageNumber:pageNum,
					pageSize:pageSize
				});
				dg.treegrid("loadData",state.originalRows);
			}
		});

		if (!state.originalRows){
			state.originalRows = data.rows;
		}

		let topRows = [];
		let childRows = [];

		$.map(state.originalRows, function(row){
			row._parentId ? childRows.push(row) : topRows.push(row);
		});

		data.total = topRows.length;

		let start = (opts.pageNumber-1)*parseInt(opts.pageSize);
		let end = start + parseInt(opts.pageSize);

		data.rows = $.extend(true,[],topRows.slice(start, end).concat(childRows));

		return data;
	}

	let appendMethod = $.fn.treegrid.methods.append;
	let loadDataMethod = $.fn.treegrid.methods.loadData;

	$.extend($.fn.treegrid.methods, {
		clientPaging: function(jq) {
			return jq.each(function() {
				let state = $(this).data("treegrid");
				let opts = state.options;
				opts.loadFilter = pagerFilter;
				let onBeforeLoad = opts.onBeforeLoad;

				opts.onBeforeLoad = function(row,param) {
					state.originalRows = null;
					onBeforeLoad.call(this, row, param);
				}
				$(this).treegrid("loadData", state.data);
				$(this).treegrid("reload");
			});
		},
		loadData: function(jq, data) {
			jq.each(function() {
				$(this).data("treegrid").originalRows = null;
			});

			return loadDataMethod.call($.fn.treegrid.methods, jq, data);
		},
		append: function(jq, param) {
			return jq.each(function() {
				let state = $(this).data("treegrid");

				if (state.options.loadFilter == pagerFilter){
					$.map(param.data, function(row) {
						row._parentId = row._parentId || param.parent;
						state.originalRows.push(row);
					});
					$(this).treegrid("loadData", state.originalRows);
				} else {
					appendMethod.call($.fn.treegrid.methods, jq, param);
				}
			})
		}
	});
})(jQuery);

三、具体业务逻辑

添加数据

当点击添加按钮的时候,会在表格末尾添加一行记录,并开启行编辑,使用了sessionStorage保存正在编辑的行数据的ID。

/**
 * 添加
 */
function insert() {
	let menuId = new Date().getTime();
	let treegrid = $("#menu_treegrid");

	treegrid.treegrid("append",{
		data: [{
			id: menuId,
			name: "xxx",
			url: "/html/xxx",
			icon: "icon-xxx"
		}]
	});

	// 保存editingId到sessionStorage
	storage("editingId", menuId);
	
	// 开启行编辑
	treegrid.treegrid("beginEdit", menuId);
}

保存数据

点击保存会修改editingId的值为undefined,相当于删除

/**
 * 保存
 */
function save() {
	let editingId = getStorage("editingId");

	if (editingId) {
		let treegrid = $("#menu_treegrid");

		if (editingId) {
			// 只有结束编辑才能获取到最新的值
			treegrid.treegrid("endEdit", editingId);

			let postData = {
				id: editingId,
				name: data.name,
				url: data.url,
				icon: data.icon,
				parentId: parentId
			};

			console.log(postData);

            // 修改editingId的值为undefined,相当于删除
			storage("editingId", undefined);

			// post("/menu/updateById", postData, function () {
			// 	storage("editingId", undefined);
			// }, error);
		}
	}
}

编辑数据

选中表格一行,点击编辑按钮,就会根据editingId的值来判断当前有没有行在编辑,如果有的话,选中当前行,但是不结束正在编辑的行。如果没有在编辑的数据行,则开启当前选中行的编辑。

/**
 * 修改
 */
function edit() {
	let editingId = getStorage("editingId");

	console.log(editingId);

	if (editingId) {
		$("#menu_treegrid").treegrid("select", editingId);
	} else {
		let row = $("#menu_treegrid").treegrid("getSelected");

		console.log("开始编辑行:");
		console.log(row);

		if (row) {
			storage("editingId", row.id);

			$("#menu_treegrid").treegrid("beginEdit", row.id);
		}
	}
}

四、问题分析

点击修改按钮无反应,但是并没有报错,问题很显然,是一直走的if分支,一直在选中当前行。

所以,问题的关键就在editingId的值,上面通过浏览器打印出来的值为undefined,很显然没有什么问题。

但是,致命的就是这里,这里打印的undefined并不是未定义,而是字符串的"undefined"。

直接打印undefined是灰色的,如图,下面的那个是真的undefined

五、问题解决

既然不能直接存undefined,那么就存一个空字符串进去,问题完美解决~

/**
 * 保存
 */
function save() {
	let editingId = getStorage("editingId");

	if (editingId) {
		let treegrid = $("#menu_treegrid");

		if (editingId) {
			// 只有结束编辑才能获取到最新的值
			treegrid.treegrid("endEdit", editingId);

			let postData = {
				id: editingId,
				name: data.name,
				url: data.url,
				icon: data.icon,
				parentId: parentId
			};

			console.log(postData);
			storage("editingId", "");
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1156230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CN考研真题知识点二轮归纳(3)

持续更新&#xff0c;上期目录&#xff1a; CN考研真题知识点二轮归纳&#xff08;2&#xff09;https://blog.csdn.net/jsl123x/article/details/134111760?spm1001.2014.3001.5501 1.TCP/IP 名称&#xff1a;传输控制协议/网络协议&#xff0c;是一个协议族&#xff0c;主…

机器人仿真——gazebo学习笔记(0)

Gazebo是一个功能强大的三维物理仿真平台&#xff0c;具有强大的物理引擎、高质量的图形渲染能力、重点是他是开源的、免费的。 1.Gazebo具备以下几个特点: 1.动力学仿真:支持多种高性能物理引擎,像ODE、Bullet等. 2.三维可视化环境:x、y、z三维环境。 3.传感器仿真:支持传…

【MATLAB】全网唯一的13种信号分解+FFT傅里叶频谱变换联合算法全家桶

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 大家吃一顿火锅的价格便可以拥有13种信号分解FFT傅里叶频谱变换联合算法&#xff0c;绝对不亏&#xff0c;知识付费是现今时代的趋势&#xff0c;而且都是我精心制作的教程&#xff0c;有问题可随时反馈~也可单独获取某一…

数据仓库-拉链表

在数据仓库中制作拉链表&#xff0c;可以按照以下步骤进行&#xff1a; 确定需求&#xff1a;首先明确需要使用拉链表的场景和需求。例如&#xff0c;可能需要记录历史数据的变化&#xff0c;以便进行时间序列分析等。设计表结构&#xff1a;在数据仓库中&#xff0c;拉链表通…

uniapp 使用 UDP

一、搭建UDP服务端&#xff0c;nodejs const dgram require("dgram");const message Buffer.from("你好&#xff0c;这是一个UDP广播消息"); const port 3000; // 用你想要的端口替换这里// 创建一个UDP套接字 const socket dgram.createSocket("…

《TCP/IP详解 卷一:协议》第5章的IPv4数据报的IHL字段解释

首先说明一下&#xff0c;这里并不解释整个IPv4数据报各个字段的含义&#xff0c;仅仅针对IHL字段作解释。 我们先看下IPv4数据报格式 对于IHL字段&#xff0c; 《TCP/IP详解 卷一&#xff1a;协议》这么解释&#xff1a; IPv4数据报。头部大小可变&#xff0c;4位的IHL字段…

队列的链式存储结构与实现

前言 在前面我们学习了队列的概念与循环队列&#xff0c;我们知道了循环链表的队列长度事先就得确定好&#xff0c;但是实际中队列长度我们事先大多不知道&#xff0c;所以还是得研究一下动态的队列长度的队列储存与实现。 虽然顺序存储也可以通过realloc来实现扩容&#xff0c…

使用Postman快速复现浏览器的请求(包括生成调用代码)

前言 大家好&#xff01;我是sum墨&#xff0c;一个一线的底层码农&#xff0c;平时喜欢研究和思考一些技术相关的问题并整理成文&#xff0c;限于本人水平&#xff0c;如果文章和代码有表述不当之处&#xff0c;还请不吝赐教。 好久没有写开发类的工具使用文了&#xff0c;这…

Tigger绕过激活锁/屏幕锁隐藏工具,支持登入iCloud有消息通知,支持iOS12.0-14.8.1。

绕过激活锁工具Tigger可以用来帮助因为忘记自己的ID或者密码而导致iPhone/iPad无法激活的工具来绕过自己的iPhone/iPad。工具支持Windows和Mac。 工具支持的功能&#xff1a; 1.Hello界面两网/三网/无基带/乱码绕过&#xff0c;可以完美重启&#xff0c;支持iCloud登录、有消…

Leetcode—2.两数相加【中等】

2023每日刷题&#xff08;十五&#xff09; Leetcode—2.两数相加 迭代法实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l…

损坏的视频不能观看,还能修复吗?

3-1 在日常的生活或者工作中&#xff0c;特别是做摄像工作的人&#xff0c;有一定的概率会遇到损坏的视频文件&#xff0c;比如相机突然断电、无人机炸机等&#xff0c;都有可能导致保存的视频文件损坏。 如果遇到这种情况&#xff0c;该如何修复这种损坏的视频文件&#xff…

[架构之路-248/创业之路-79]:目标系统 - 纵向分层 - 企业信息化的呈现形态:常见企业信息化软件系统 - 供应链管理

目录 前言&#xff1a; 一、企业信息化的结果&#xff1a;常见企业信息化软件 1.1 供应链管理 1.1 什么是供应链与供应链管理What 1.2 为什么需要供应链管理系统Why&#xff1f; 1.3 谁需要供应链管理系统who&#xff1f; 1.4 供应链管理在企业管理中的位置where 1.5 什…

CS224W4.1——PageRank

在这篇中&#xff0c;我们将关注如何将图表示为矩阵&#xff0c;并讨论我们可以探索的后续属性。我们定义了PageRank的概念&#xff0c;进一步探索随机游走&#xff0c;并引入矩阵分解作为生成节点嵌入的视角。在第一部分&#xff0c;我们将介绍PageRank作为在图中对节点重要性…

mybarisplus插件(分页与乐观锁)

文章目录 1.分页插件2.自定义分页3.乐观锁3.1 场景3.2 乐观锁与悲观锁3.3 模拟修改冲突3.4 乐观锁解决问题 1.分页插件 MyBatis Plus自带分页插件&#xff0c;只要简单的配置即可实现分页功能 添加配置类MyBatisPlusConfig Configuration MapperScan("com.atguigu.mybatis…

Cordova插件开发二:高精度定位之卫星数据解析

文章目录 1.最终效果预览2.坐标获取方法3.在公共类中封装获取坐标的通用方法4.插件js中封装startGeoLocation方法5.插件主界面封装的方法1.最终效果预览 2.坐标获取方法 let obj = Object.assign({}, this.mapConfig.mapLocationObj)obj.isKeepCallBack = falselet res = await…

v免签易支付二开版源码+pc端订单监控+支付宝免挂机可回调

v免签二开版&#xff0c;又叫做v免签易支付版。它相当于是通过易支付的方式对接&#xff0c;不用单独搭建易支付系统了 安装教程 1、网站目录->运行目录 设置为public并保存 2、伪静态 设置为thinkphp并保存 3、打开网站目录 config/database.php &#xff0c;设置好您的m…

cdrx8和2020哪个版本更好用?有什么区别

经过多年的发展&#xff0c;cdr推出了很多优秀的版本&#xff0c;并顺应时代的发展更新了多项功能。随着cdr推出的软件版本增多&#xff0c;小伙伴们可选择的产品也在增多&#xff0c;那么该怎么选择呢&#xff1f;本文会给大家介绍cdrx8和2020的区别&#xff0c;CDRX8和2020哪…

大语言模型(LLM)综述(五):使用大型语言模型的主要方法

A Survey of Large Language Models 前言6 UTILIZATION6.1 In-Context Learning6.1.1 提示公式6.1.2 演示设计6.1.3 底层机制 6.2 Chain-of-Thought Prompting6.2.1 CoT的上下文学习6.2.2 关于CoT的进一步讨论 6.3 Planning for Complex Task Solving6.3.1 整体架构6.3.2 计划生…

【css3】涟漪动画

效果展示 dom代码 <div class"mapSelfTitle66"><div></div> </div> 样式代码 .mapSelfTitle66{width:120px;height:60px;position: relative;&>div{width:100%;height:100%;background: url("~/assets/images/video_show/err…