IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 10分钟快速实现vue的数据双向绑定 -> 正文阅读

[JavaScript知识库]10分钟快速实现vue的数据双向绑定

概念

双向绑定概念其实很简单,就是视图(View)的变化能实时让数据模型(Model)发生变化,而数据的变化也能实时更新到视图层。我们所说的单向数据绑定就是从数据到视图这一方向的关系。

分析

1、响应式数据

使用Object.defineProperty、Proxy对数据进行监听拦截。

//obj:必需。目标对象
//prop:必需。需定义或修改的属性的名字
//descriptor:必需。目标属性所拥有的特性
Object.defineProperty(obj, prop, descriptor)

vue3.0 开始 Proxy代替Object.defineProperty

let p = new Proxy(target, handler);

2、input事件监听

绑定事件处理函数,实时修改数据。

3、相关dom操作

将数据与相关dom节点绑定在一起,修改数据的时候对应的dom节点也应一起改变。

实现

1、html页面

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>v-model</title>
	</head>
	<body>
		<div id="app">
			<input type="text" v-model="name" placeholder="姓名"/>
			<input type="text" v-model="age" placeholder="年龄"/>
			<div>
				<p>
					姓名:<span>{{name}}</span>
				</p>
				<p>
					年龄:<span>{{age}}</span>
				</p>
				<p>
					<p>
						年龄:<span>{{age}}</span>
					</p>
				</p>
			</div>
			<button id="btn">修改名字</button>
		</div>
	</body>
	<script src="./VModel.js"></script>
	<script>
		const app = new VModel('#app',{
			name:'',
			age:''
		});
		document.getElementById('btn').addEventListener('click',function() {
			app.setData('name','名字改变了');
		})
	</script>
</html>

在这里插入图片描述

2、VModel.js

(1)构造VModel

class  VModel {
	constructor(el,data) {
		this.el = document.querySelector(el);
		//存放数据对象
		this._data = data;
		//存放绑定数据的dom节点
		this.domPoll = {};
		
		this.init();
	}
}

(2)初始化数据对象

使用Object.defineProperty
initData () {
	const _this = this;
	this.data = {};
	for(let key in this._data){
		Object.defineProperty(this.data,key,{
			get(){
				console.log("获取数据",key,_this._data[key]);
				return _this._data[key];
			},
			set(newVal){
				console.log("设置数据",key,newVal);
				_this.domPoll[key].innerText = newVal;
				_this._data[key] = newVal;
			}
		});
	}
}
使用Proxy
initData () {
	const _this = this;
	this.data = {};
	this.data = new Proxy(this.data,{
		get(target,key){
			return Reflect.get(target,key);
		},
		set(target,key,value){
			// _this.domPoll[key].innerText = value;
			_this.domPoll[key].forEach(item => {
				item.innerText = value;
			})
			return Reflect.set(target,key,value);
		}
	})
}

(3)绑定dom节点

bindDom(el){
	const childNodes = el.childNodes;
	childNodes.forEach(item => {
		//nodeType为3时该dom节点为文本节点
		if(item.nodeType === 3){
			const _value = item.nodeValue;
		
			if(_value.trim().length){
				//匹配是否有两个花括号包裹的数据
				let  _isValid = /\{\{(.+?)\}\}/.test(_value);
				if(_isValid){
					const _key = _value.match(/\{\{(.+?)\}\}/)[1].trim();
					// this.domPoll[_key] = item.parentNode;
					//一个数据可以被多个dom节点绑定,所以应该用数组来进行保存
						//未定义时先初始化
						if(!this.domPoll[_key]) this.domPoll[_key] = [];
						this.domPoll[_key].push(item.parentNode);
					//替换绑定的值
					item.parentNode.innerText = this.data[_key] || undefined;
				}
			}
		}
		//递归遍历子节点
		item.childNodes && this.bindDom(item);
	})
}

####(4)输入框数据绑定

bindInput(el){
	//获取input所有元素节点
	const _allInput = el.querySelectorAll('input');
	_allInput.forEach(input => {
		const _vModel = input.getAttribute('v-model');
		//判断是否有v-model属性
		if(_vModel){
//监听输入事件			input.addEventListener('keyup',this.handleInput.bind(this,_vModel,input),false);
		}
	})
}

handleInput(key,input){
	const _value = input.value;
	//数据变化的时候会同步修改dom节点绑定的数据。
	this.data[key] = _value;
}

(4)完整代码

class  VModel {
	constructor(el,data) {
		this.el = document.querySelector(el);
		this._data = data;
		this.domPoll = {};
		
		this.init();
	}
	
	init(){
		this.initData();
		this.initDom();
	}
	initDom(){
		this.bindDom(this.el);
		this.bindInput(this.el);
		console.log('domPoll',this.domPoll);
	}
	
	initData () {
		const _this = this;
		this.data = {};
		// for(let key in this._data){
		// 	Object.defineProperty(this.data,key,{
		// 		get(){
		// 			console.log("获取数据",key,_this._data[key]);
		// 			return _this._data[key];
		// 		},
		// 		set(newVal){
		// 			console.log("设置数据",key,newVal);
		// 			_this.domPoll[key].innerText = newVal;
		// 			_this._data[key] = newVal;
		// 		}
		// 	});
		// }
		this.data = new Proxy(this.data,{
			get(target,key){
				return Reflect.get(target,key);
			},
			set(target,key,value){
				// _this.domPoll[key].innerText = value;
				_this.domPoll[key].forEach(item => {
					item.innerText = value;
				})
				return Reflect.set(target,key,value);
			}
		})
	}
	
	bindDom(el){
		const childNodes = el.childNodes;
		childNodes.forEach(item => {
			if(item.nodeType === 3){
				const _value = item.nodeValue;
			
				if(_value.trim().length){
					let  _isValid = /\{\{(.+?)\}\}/.test(_value);
					if(_isValid){
						const _key = _value.match(/\{\{(.+?)\}\}/)[1].trim();
						// this.domPoll[_key] = item.parentNode;
						if(!this.domPoll[_key]) this.domPoll[_key] = [];
						this.domPoll[_key].push(item.parentNode);
						item.parentNode.innerText = this.data[_key] || undefined;
					}
				}
			}
			
			item.childNodes && this.bindDom(item);
		})
	}
	
	bindInput(el){
		const _allInput = el.querySelectorAll('input');
		_allInput.forEach(input => {
			const _vModel = input.getAttribute('v-model');
			
			if(_vModel){
				input.addEventListener('keyup',this.handleInput.bind(this,_vModel,input),false);
			}
		})
	}
	
	handleInput(key,input){
		const _value = input.value;
		this.data[key] = _value;
		// console.log(this.data);
	}
	
	setData(key,value){
		this.data[key] = value;
	}
}

在这里插入图片描述

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-14 13:14:30  更:2021-09-14 13:16:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 14:06:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计