storage数据存储问题,不能存undefined

news2024/11/19 11:26:16

这篇文章分享一下自己使用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/1155220.html

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

相关文章

操作系统的内存管理之虚拟空间

操作系统的内存管理&#xff0c;主要分为三个方面。 第一&#xff0c;物理内存的管理&#xff0c;相当于会议室管理员管理会议室。 第二&#xff0c;虚拟地址的管理&#xff0c;也即在项目组的视角&#xff0c;会议室的虚拟地址应该如何组织。 第三&#xff0c;虚拟地址和物…

vcomp140.dll丢失是什么意思,vcomp140.dll丢失这几个方法都能修复好

vcomp140.dll是什么&#xff1f; vcomp140.dll是一个动态链接库&#xff08;Dynamic Link Library&#xff09;&#xff0c;它主要用于支持Microsoft Visual C 2015编程语言的运行。这个文件包含了编译器相关的函数和资源&#xff0c;对于使用Visual C 2015开发的程序和游戏来…

Android图形系统之HWComposer、ComposerHal、ComposerImpl、Composer、Hwc2::Composer实例总结(十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

一款Nacos漏洞自动化工具

1、参考GitHub - charonlight/NacosExploitGUI: Nacos漏洞综合利用GUI工具&#xff0c;集成了默认口令漏洞、SQL注入漏洞、身份认证绕过漏洞、反序列化漏洞的检测及其利用 0x01 前言 ​ 本工具已经集成Nacos常见漏洞的检测及其利用&#xff0c;工具为GUI版本&#xff0c;简单…

[迁移学习]DA-DETR基于信息融合的自适应检测模型

原文标题为&#xff1a;DA-DETR: Domain Adaptive Detection Transformer with Information Fusion&#xff1b;发表于CVPR2023 一、概述 本文所描述的模型基于DETR&#xff0c;DETR网络是一种基于Transformer的目标检测网络&#xff0c;详细原理可以参见往期文章&#xff1a;…

k8s 资源预留

KUBERNETES资源管理之–资源预留 Kubernetes 的节点可以按照 Capacity 调度。node节点本身除了运行不少驱动 OS 和 Kubernetes 的系统守护进程&#xff0c;默认情况下 pod 能够使用节点全部可用容量&#xff0c; 除非为这些系统守护进程留出资源&#xff0c;否则它们将与 pod 争…

创造产业链协同优势后,凌雄科技在DaaS行业转动成长飞轮

企业服务领域&#xff0c;一直存在一种共识&#xff1a;做好很难&#xff0c;但一旦服务模式跑通了&#xff0c;得到了市场的认可&#xff0c;要滚起雪球就会事半功倍。 重资产、重运营的DaaS&#xff08;设备及服务&#xff09;赛道&#xff0c;是个非常典型的细分领域。在这…

泡泡玛特首度跨界超跑品牌兰博基尼汽车,以潮流基因探索时空边界

近期&#xff0c;泡泡玛特携手兰博基尼汽车&#xff0c;于上海国际赛车场进行了一场玩味十足的赛道体验。25位兰博基尼车主&#xff0c;及多位汽车领域知名媒体人、kol到场参与。兰博基尼跑车巡游、专业车手驾驶的兰博基尼涂装赛车试乘、MEGA SPACE MOLLY 1000%/400%兰博基尼汽…

深入理解计算机系统CS213学习笔记

Lecture 01 1. 计算机表示数字 int 整数运算可能会出现错误&#xff0c;超过32位时会出现溢出。 float 浮点数不适用结合律&#xff0c;因为浮点数表示的精度有限。 根其原因&#xff0c;是用有限的位数表示无限的数字空间。 2.利用分层的存储系统&#xff0c;使程序运行更…

第三届字节跳动奖学金官宣开奖,13位优秀科研学子每人获10万奖学金

最近&#xff0c;第三届字节跳动奖学金正式公布了获奖者名单。 经过字节跳动技术专家团队层层评审&#xff0c;本届字节跳动奖学金共有来自北京大学、复旦大学、清华大学、上海交通大学、香港科技大学、浙江大学、中国科学技术大学&#xff08;按拼音首字母排序&#xff09;的 …

MyBatis-Plus返回getOne返回null疑惑

getOne返回null 问题描述分析过程总结 问题描述 在数据库建了一张表主要包括两个字段master_id和slave_id;主要的额外字段max_lots 默认值是null&#xff1b;当调用getOne进行查询是&#xff0c;返回是null 分析过程 总结

MFC String类的初始化学习

之前写过CString的用法&#xff1b; VC CString 编程实例图解_bcbobo21cn, cstring-CSDN博客 下面单独看一下CString的各种初始化方式&#xff1b; void CTest2View::OnDraw(CDC* pDC) {CTest2Doc* pDoc GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for nati…

Servlet 初始化参数(web.xml和@WebServlet)

1、通过web.xml方式 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://xmlns.jcp.org/xm…

三十九、CANdelaStudio实践-19服务(ReadDTCInformation)

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的19服务(ReadDTCInformation)编辑,欢迎…

【C++】C++11常见特性

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

基于静电放电算法的无人机航迹规划-附代码

基于静电放电算法的无人机航迹规划 文章目录 基于静电放电算法的无人机航迹规划1.静电放电搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用静电放电算法来优化无人机航迹规划。 …

电脑加密软件哪个好?电脑加密软件推荐

电脑是我们办公离不开的工具&#xff0c;而为了保护电脑数据安全&#xff0c;我们可以使用专业的电脑加密软件来进行加密保护。那么&#xff0c;电脑加密软件哪个好呢&#xff1f;下面我们就来了解一下。 文件加密——超级加密3000 想要安全加密电脑重要文件&#xff0c;我们可…

SAM:Segment Anything 代码复现和测试 基本使用

相关地址 代码&#xff1a; https://github.com/facebookresearch/segment-anything 在线网站&#xff1a; https://segment-anything.com/demo 环境配置 建议可以clone下来学习相关代码&#xff0c;安装可以不依赖与这个库 git clone https://github.com/facebookresearch…

计算机毕业设计选题推荐-大学生校园兼职微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

unittest与pytest的区别

Unittest vs Pytest 主要从用例编写规则、用例的前置和后置、参数化、断言、用例执行、失败重运行和报告这几个方面比较unittest和pytest的区别: 用例编写规则 用例前置与后置条件 断言 测试报告 失败重跑机制 参数化 用例分类执行 如果不好看&#xff0c;可以看下面表格&…