首页 > 其他分享 >模仿实现Vue的双向绑定

模仿实现Vue的双向绑定

时间:2024-04-26 12:00:12浏览次数:11  
标签:vue obj 绑定 param Vue key 双向 data

简单模仿Vue的单项绑定和双向绑定,可以解析v-bind和v-mode标签

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>模拟Vue单向绑定和双向绑定</title>
	</head>
	<body>
		<div id="app">
			<input type="text"   :key="number" v-model="name"><br>
			<br>
			<input type="text"   :key="number" v-model="name"><br>
			<br>
			<div>
				<input type="text"   :key="name" v-model="number"><br>
				<input type="text"   :key="name" v-model="number"><br>
			</div>
			<button type="button" onclick="showData()">查看data</button>
			<button type="button" onclick="changeData()">修改data</button>
		</div>
		<script>
			//定义Vue
			window.Vue = function(option) {
				var _vue = new Object();
				if (!option) {
					throw "配置参数错误";
				}

				_vue.$option = option;
				//获取根元素
				_vue._el = option.el;
				//获取data
				_vue._data = option.data;

				let elementArr = new Array();

				//劫持data
				function proxyData() {
					for (key in _vue._data) {
						let _key = key;
						Object.defineProperty(_vue, _key, {
							get() {
								console.log("获取" + _key + "的值");
								return _vue._data[_key];
							},
							set(value) {
								console.log("设置" + _key + "的值");
								_vue._data[_key] = value;
								//更新单项绑定的元素
								let elViewArr = _vue["_" + _key + "_view"];
								if (elViewArr) {
									elViewArr.forEach(el => {
										el.element.setAttribute(el.keyName, value);
									});
								}
								//更新双向绑定的元素
								let elViewModelArr = _vue["_" + _key + "_view_model"];
								if (elViewModelArr) {
									elViewModelArr.forEach(el => {
										el.element.value = value;
									});
								}
							}
						})
					}
				}

				//获取所有元素
				function parseElement(root) {
					//解析每一个元素和子元素
					for (var i = 0; i < root.children.length; i++) {
						let child = root.children[i];
						if (child.children.length > 0) {
							//递归遍历
							parseElement(child);
						} else {
							elementArr.push(child);
						}
					}
				}


				//渲染节点
				function render(obj) {

					if (!obj instanceof HTMLElement) {
						return;
					}
					//渲染
					let attrNames = obj.getAttributeNames();
					console.log(attrNames);
					for (_name in attrNames) {
						let _key = attrNames[_name];
						//console.log(_key);
						let param = obj.getAttribute(_key)
						//console.log(param);
						//v-bind解析
						if (_key.indexOf(":") >= 0 || _key.indexOf("v-bind:") >= 0) {
							//单向绑定
							if (_vue[param] == undefined) {
								throw param + "没有定义";
							}
							//移除现有key
							obj.removeAttribute(_key);
							//增加新key
							let tmpKey = _key.substr(_key.indexOf(":") + 1);
							obj.setAttribute(tmpKey, _vue[param]);

							//记录单项绑定的view对象
							if (!_vue["_" + param + "_view"]) {
								_vue["_" + param + "_view"] = new Array();
							}
							_vue["_" + param + "_view"].push({
								keyName: tmpKey,
								element: obj,
								valueName: param
							});
						}
						//v-mode解析
						if (_key.toLowerCase() == "v-model") {
							//双向绑定
							if (!obj.type) {
								continue;
							}
							obj.removeAttribute(_key);
							switch (obj.type) {
								case "text":
									if (_vue[param] == undefined) {
										throw param + "没有定义"
									}
									//将绑定该变量的所有对象存到数组中
									if (!_vue["_" + param + "_view_model"]) {
										_vue["_" + param + "_view_model"] = new Array();
									}
									_vue["_" + param + "_view_model"].push({
										element: obj,
										valueName: param
									});
									//双向绑定操作  M--->V 先赋值
									obj.value = _vue[param];
									//V----->M
									obj.oninput = function() {
										_vue[param] = obj.value;
									}
									//M----->V M更新时可以变更V

									break;
								default:
									break;
							}
						}
					}

				}

				//显示实时的data数据
				_vue.showData = function() {
					alert(JSON.stringify(_vue._data));
				}
				
				//初始化页面元素
				_vue.init = function(){
					//劫持data
					proxyData();
					//获取所有元素
					parseElement(document.getElementById(_vue._el));
					
					//渲染元素
					elementArr.forEach(element => {
						render(element);
					});
				}

				_vue.init();

				return _vue;
			}

			var vm = new Vue({
				el: "app",
				data: {
					number: 20,
					name: "李四"
				}
			});
		</script>
		<script type="text/javascript">
			function showData() {
				
				vm.showData();
			}
		
			function changeData() {
				vm.number = Date.now();
				vm.name = "哈哈哈" + Date.now();
			}
			
			
			let str1 = "name";
			//-----
			vm[str1]
			console.log(result);
		</script>
	</body>
</html>

标签:vue,obj,绑定,param,Vue,key,双向,data
From: https://www.cnblogs.com/bcde/p/18159761

相关文章

  • VUE Element Plus-table动态添加删除行
     <template><divclass="app-container"><el-rowstyle="margin-top:20px"><el-col:span="24"style="border-left:5pxsolid#1d6ced;margin-bottom:10px"><labelstyle=......
  • vue3+vite+js 引用public文件夹中js文件
    vue的public的资源在打包时不会被编译,只会copy所以在在src路径下引入public文件夹下的图片、视频、音频,编译不会改变其路径,但是在src下引入public文件夹下的js、json,在打包时都会被编译,所以直接引入会丢失路径(因为打包时,当前页面引入的路径被hash打包,而public文件夹下只是被cop......
  • v-for 循环时直接使用 v-model 绑定报错
    报错信息:Youarebindingv-modeldirectlytoav-foriterationalias.Thiswillnotbeabletomodifythev-forsourcearraybecausewritingtothealiasislikemodifyingafunctionlocalvariable. 错误代码<divv-for="(item,index)indata":key......
  • 2024年vue 开发环境 Node.js于win10环境下的安装
    2024年vue开发环境Node.js于win10环境下的安装导航2024年vue开发环境Node.js于win10环境下的安装导航一、下载node.js二、安装node.js三、测试(一)四、环境配置五、测试(二)六、安装淘宝镜像七、安装vue脚手架一、下载node.jsNode.js官方网站下载:https://nodejs.org/en......
  • 双向循环链表的删除、插入
    双向循环链表双向循环链表是一种特殊的链表结构,它结合了双向链表和循环链表的特点。在双向循环链表中,每个节点都有两个指针,一个指向前一个节点,另一个指向后一个节点,从而形成双向链接。同时,链表的头节点和尾节点相互链接,形成一个循环结构。这种结构使得双向循环链表在遍历和操作......
  • 双向循环链表的插入处理函数接口
    //方便访问,创建一个带头结点的双向循环链表//链表数据域取别名方便修改typedefintDataType_t;//构造双向循环链表的结点typedefstructDoubleCircularLList{DataType_tdata;//数据域structDoublLingkedList*prev;//直接前驱指针域......
  • 关于双向循环列表的插入、删除、遍历
    目录双向循环链表公式初始化双向循环链表构建双向循环链表结构体//双向循环链表节点定义typedefstructdouble_loop_node{chardata[DATA_LEN];//数据域,存储数据长度structdouble_loop_node*next;......
  • 02-属性事件过滤双向绑定
    es6的对象写法//正常的写法letarr=['逃课','打游戏','欺负小满']lethobbyDetail={name:"大乔",age:4,hobby:arr}console.log(hobbyDetail)//简写//正常的写法letarr=['逃课','打游戏','欺负小满'......
  • 双向链表的学习
    双向链表的学习经过单链表、双链表的学习,可以总结链表的适用场合:适合用于节点数目不固定,动态变化较大的场合适合用于节点需要频繁插入、删除的场合适合用于对节点查找效率不十分敏感的场合双向链表的增删改查实现双向链表的初始化//指的是双向链表中的节点有效数据......
  • 【vue3入门】-【13】class绑定
    class绑定数据绑定的一个常见需求场景是操纵元素的CSSclass列表,因为class是Attribute,我们可以和其他Attribute一样使用v-bind将它们动态的字符串绑定。但是,在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且易出错的。因此,vue专门为class和v-bind用法提供了特殊的功能增强。除......