用ES6的class模仿Vue写一个双向绑定的示例代码
程序员文章站
2022-09-03 14:40:35
本文介绍了用es6的class模仿vue写一个双向绑定的示例代码,分享给大家,具体如下:
最终效果如下:
构造器(constructor)
构造一个tin...
本文介绍了用es6的class模仿vue写一个双向绑定的示例代码,分享给大家,具体如下:
最终效果如下:
构造器(constructor)
构造一个tinyvue对象,包含基本的el,data,methods
class tinyvue{ constructor({el, data, methods}){ this.$data = data this.$el = document.queryselector(el) this.$methods = methods // 初始化 this._compile() this._updater() this._watcher() } }
编译器(compile)
用于解析绑定到输入框和下拉框的v-model和元素的点击事件@click。
先创建一个函数用来载入事件:
// el为元素tagname,attr为元素属性(v-model,@click) _initevents(el, attr, callback) { this.$el.queryselectorall(el).foreach(i => { if(i.hasattribute(attr)) { let key = i.getattribute(attr) callback(i, key) } }) }
载入输入框事件
this._initevents('input, textarea', 'v-model', (i, key) => { i.addeventlistener('input', () => { object.assign(this.$data, {[key]: i.value}) }) })
载入选择框事件
this._initevents('select', 'v-model', (i, key) => { i.addeventlistener('change', () => object.assign(this.$data, {[key]: i.options[i.options.selectedindex].value})) })
载入点击事件
点击事件对应的是methods中的事件
this._initevents('*', '@click', (i, key) => { i.addeventlistener('click', () => this.$methods[key].bind(this.$data)()) })
视图更新器(updater)
同理先创建公共函数来处理不同元素中的视图,包括input、textarea的value,select的选择值,div的innerhtml
_initview(el, attr, callback) { this.$el.queryselectorall(el, attr, callback).foreach(i => { if(i.hasattribute(attr)) { let key = i.getattribute(attr), data = this.$data[key] callback(i, key, data) } }) }
更新输入框视图
this._initview('input, textarea', 'v-model', (i, key, data) => { i.value = data })
更新选择框视图
this._initview('select', 'v-model', (i, key, data) => { i.queryselectorall('option').foreach(v => { if(v.value == data) v.setattribute('selected', true) else v.removeattribute('selected') }) })
更新innerhtml
这里实现方法有点low,仅想到正则替换{{text}}
let regexpinner = /\{{ *([\w_\-]+) *\}}/g this.$el.queryselectorall("*").foreach(i => { let replacelist = i.innerhtml.match(regexpinner) || (i.hasattribute('vueid') && i.getattribute('vueid').match(regexpinner)) if(replacelist) { if(!i.hasattribute('vueid')) { i.setattribute('vueid', i.innerhtml) } i.innerhtml = i.getattribute('vueid') replacelist.foreach(v => { let key = v.slice(2, v.length - 2) i.innerhtml = i.innerhtml.replace(v, this.$data[key]) }) } })
监听器(watcher)
数据变化之后更新视图
<div id="app"> <input type="text" v-model="text1"><br> <input type="text" v-model="text2"><br> <textarea type="text" v-model="text3"></textarea><br> <button @click="add">加一</button> <h1>您输入的是:{{text1}}+{{text2}}+{{text3}}</h1> <select v-model="select"> <option value="volvo">volvo</option> <option value="saab">saab</option> </select> <select v-model="select"> <option value="volvo">volvo</option> <option value="saab">saab</option> </select> <h1>您选择了:{{select}}</h1> </div> <script src="./tinyvue.js"></script> <script> let app = new tinyvue({ el: '#app', data: { text1: 123, text2: 456, text3: '文本框', select: 'saab' }, methods: { add() { this.text1 ++ this.text2 ++ } } }) </script>
tinyvue全部代码
class tinyvue{ constructor({el, data, methods}){ this.$data = data this.$el = document.queryselector(el) this.$methods = methods this._compile() this._updater() this._watcher() } _watcher(data = this.$data) { let that = this object.keys(data).foreach(i => { let value = data[i] object.defineproperty(data, i, { enumerable: true, configurable: true, get: function () { return value; }, set: function (newval) { if (value !== newval) { value = newval; that._updater() } } }) }) } _initevents(el, attr, callback) { this.$el.queryselectorall(el).foreach(i => { if(i.hasattribute(attr)) { let key = i.getattribute(attr) callback(i, key) } }) } _initview(el, attr, callback) { this.$el.queryselectorall(el, attr, callback).foreach(i => { if(i.hasattribute(attr)) { let key = i.getattribute(attr), data = this.$data[key] callback(i, key, data) } }) } _updater() { this._initview('input, textarea', 'v-model', (i, key, data) => { i.value = data }) this._initview('select', 'v-model', (i, key, data) => { i.queryselectorall('option').foreach(v => { if(v.value == data) v.setattribute('selected', true) else v.removeattribute('selected') }) }) let regexpinner = /\{{ *([\w_\-]+) *\}}/g this.$el.queryselectorall("*").foreach(i => { let replacelist = i.innerhtml.match(regexpinner) || (i.hasattribute('vueid') && i.getattribute('vueid').match(regexpinner)) if(replacelist) { if(!i.hasattribute('vueid')) { i.setattribute('vueid', i.innerhtml) } i.innerhtml = i.getattribute('vueid') replacelist.foreach(v => { let key = v.slice(2, v.length - 2) i.innerhtml = i.innerhtml.replace(v, this.$data[key]) }) } }) } _compile() { this._initevents('*', '@click', (i, key) => { i.addeventlistener('click', () => this.$methods[key].bind(this.$data)()) }) this._initevents('input, textarea', 'v-model', (i, key) => { i.addeventlistener('input', () => { object.assign(this.$data, {[key]: i.value}) }) }) this._initevents('select', 'v-model', (i, key) => { i.addeventlistener('change', () => object.assign(this.$data, {[key]: i.options[i.options.selectedindex].value})) }) } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。