vue原理

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>仿vue</title>
</head>
<body>

	<div id="app">
		<input type="text" v-model = 'name'>-<input type="text" v-model = 'testData'>
		<span>输入数据为:{{name}} -- {{testData}}</span>
		<h3>合并字符串{{name+testData}}</h3>
		<h3>v-bind:</h3>
		<h3 v-bind='name'>v-bind=name</h3>
		<button v-on:click='change'>change</button>
	</div>
	
</body>
<script>
	window.onload = function(){
		var app = new myVue({
			el:"#app",
			data : {
				name:"仿vue",
				testData : "另一个数据变量"
			},
			method : {
				change:function(){
					this.name = 'change';
				}
			}
		})
	}

	function myVue(options = {}){
		this.$options = options;
		this.$el = document.querySelector(options.el);
		this._data = options.data;
		this._watcherTpl = {};
		this._methods = options.method;
		this._observer(this._data);
		this._compile(this.$el);
	}

	myVue.prototype._observer = function(obj){
		var _this = this;
		Object.keys(obj).forEach(key => {
			_this._watcherTpl[key] = {
				_directive : []
			}

			var value = obj[key];

			var watcherTpl = _this._watcherTpl[key];

			Object.defineProperty(_this._data,key,{
				configurable : true,
				enumerable : true,
				get(){
					return value;
				},
				set(newValue){
					var oldvalue = value;
					if(value !== newValue){
						value = newValue;
						watcherTpl._directive.forEach(item => {
							item.update(oldvalue);
						})
					}
				}
			});
		});
		
	}

	myVue.prototype._compile = function(el){
		var _this = this;
		var nodes = el.children;
		for (var i = 0; i < nodes.length; i++) {
			var node = nodes[i];
			if(node.children.length){
				_this._compile(node);
			}

			if(node.hasAttribute('v-model')&&(node.tagName == 'INPUT'||node.tagName == 'TEXTAREA')){
				node.addEventListener('input',(function(key){
					var attrVal = node.getAttribute('v-model');
					_this._watcherTpl[attrVal]._directive.push(new Watcher(node,_this,attrVal,'value'));
					return function(){
						_this._data[attrVal] = nodes[key].value;
					}
				})(i));
			}

			if(node.hasAttribute('v-bind')){
				var attrVal = node.getAttribute('v-bind');
				_this._watcherTpl[attrVal]._directive.push(new Watcher(node,_this,attrVal,'innerHTML'));
			}

			var reg = /\{\{\s*([^}]+\S)\s*\}\}/g;
			var txt = node.textContent;
			if(reg.test(txt)){
				 let replaceList = node.innerHTML.match(reg) || (node.hasAttribute('vueID') && node.getAttribute('vueID').match(reg))
		            if(replaceList) {
		                if(!node.hasAttribute('vueID')) {
		                    node.setAttribute('vueID', node.innerHTML)
		                }
		                node.innerHTML = node.getAttribute('vueID')
		                replaceList.forEach(v => {
		                    let key = v.slice(2, v.length - 2)
							var algorithm_reg = /[\+\-\*]/g; 
							if(algorithm_reg.test(key)){
							 var keys = key.split(algorithm_reg);
							}else{
								node.innerHTML = node.innerHTML.replace(v, this._data[key]);
								var getName = _this._watcherTpl[key];
								if(!getName._directive){
									getName._directive = [];
								}
								getName._directive.push(new Watcher(node,_this,key,'innerHTML'));
							}
		                   
		                })

		            }
				/*node.textContent = txt.replace(reg,(mathced,placeholder)=>{
  						 // matched匹配的文本节点包括{{}}, placeholder 是{{}}中间的属性名
  					var getName = _this._watcherTpl[placeholder];
  					if(!getName._directive){
  						getName._directive = [];
  					}
  					getName._directive.push(new Watcher(node,_this,placeholder,'innerHTML'));

  					
					return placeholder.split('.').reduce((val,key) => {
							return _this._data[key];
					},_this.$el);
				})*/
			}

			if(node.hasAttribute('v-on:click')){
				var methodName = node.getAttribute('v-on:click');
				node.addEventListener('click',() => this._methods[methodName].bind(this._data)());
			}

		}
	}

	function Watcher(el,vm,value,attr){
		this.el = el;
		this.vm = vm;
		this.val = value;
		this.attr = attr;
		this.update();
	}

	Watcher.prototype.update =function(oldvalue){
		if(!this.el.hasAttribute('vueID')){
			this.el[this.attr] = this.vm._data[this.val];
		}else{
			this.el[this.attr] = this.el[this.attr].replace(oldvalue, this.vm._data[this.val]);
		}
		
	}
</script>
</html>
### Vue 原理相关的面试题整理 #### 1. Vue3 的响应式原理是什么? Vue3 使用了 Proxy 来实响应式系统,相比 Vue2 中的 Object.defineProperty,Proxy 提供了更强大的功能和更好的性能[^1]。通过 Proxy 可以拦截对象的操作行为,比如属性的读取、设置以及删除等操作。 ```javascript const reactiveHandler = { get(target, key, receiver) { track(target, key); // 收集依赖 return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); trigger(target, key); // 触发更新 return result; } }; export function reactive(obj) { return new Proxy(obj, reactiveHandler); } ``` #### 2. 如何判断一个对象是否是响应式的? Vue3 提供了一些工具方法来检测对象的状态: - `isRef`:用于判断一个值是否为 Ref 对象。 - `isReactive`:用于判断一个对象是否是由 `reactive` 创建的响应式代理。 - `isReadOnly`:用于判断一个对象是否是由 `readonly` 创建的只读代理。 - `isProxy`:用于判断一个对象是否是由 `reactive` 或 `readonly` 创建的代理[^5]。 #### 3. Vue3 中 `v-if` 和 `v-for` 的优先级如何? 在 Vue3 中,`v-if` 的优先级高于 `v-for`,这与 Vue2 不同,在 Vue2 中 `v-for` 的优先级更高[^2]。因此需要注意两者结合使用的场景,避免因优先级变化而导致逻辑错误。 #### 4. Vue 过滤器的工作机制是什么? 过滤器本质上是对数据进行加工处理后再展示给用户的工具,它不会修改原始数据,而是返回一个新的经过处理的结果[^3]。可以通过链式调用多个过滤器,每个过滤器依次对前一阶段的数据进行进一步处理。 ```html {{ message | filterA("arg1", "arg2") | filterB("arg1", "arg2") }} ``` #### 5. Vue 插件是如何工作的? Vue 插件通常是一个具有 `install` 方法的对象或函数。当调用 `Vue.use(plugin)` 时,会自动执行该插件的 `install` 方法,并传入 Vue 构造器作为参数[^4]。插件可以扩展全局配置、注册组件或指令等。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值