<!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原理
最新推荐文章于 2024-10-03 16:14:13 发布