用ES6的class模仿Vue寫一個(gè)雙向綁定的示例代碼
本文介紹了用ES6的class模仿Vue寫一個(gè)雙向綁定的示例代碼,分享給大家,具體如下:
最終效果如下:
構(gòu)造器(constructor)
構(gòu)造一個(gè)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和元素的點(diǎn)擊事件@click。
先創(chuàng)建一個(gè)函數(shù)用來載入事件:
// 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})) })
載入點(diǎn)擊事件
點(diǎn)擊事件對應(yīng)的是methods中的事件
this._initEvents('*', '@click', (i, key) => { i.addEventListener('click', () => this.$methods[key].bind(this.$data)()) })
視圖更新器(updater)
同理先創(chuàng)建公共函數(shù)來處理不同元素中的視圖,包括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
這里實(shí)現(xiàn)方法有點(diǎn)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]) }) } })
監(jiān)聽器(watcher)
數(shù)據(jù)變化之后更新視圖
<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})) }) } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 原生JavaScript之es6中Class的用法分析
- ES6 class類鏈?zhǔn)嚼^承,實(shí)例化及react super(props)原理詳解
- ES6 Class中實(shí)現(xiàn)私有屬性的一些方法總結(jié)
- ES6 class的應(yīng)用實(shí)例分析
- ES6中的class是如何實(shí)現(xiàn)的(附Babel編譯的ES5代碼詳解)
- es6新特性之 class 基本用法解析
- 解讀ES6中class關(guān)鍵字
- ES6 javascript中Class類繼承用法實(shí)例詳解
- ES6 javascript中class靜態(tài)方法、屬性與實(shí)例屬性用法示例
- 詳解ES6中class的實(shí)現(xiàn)原理
相關(guān)文章
JavaScript中使用正則匹配多條,且獲取每條中的分組數(shù)據(jù)
該問題在使用Ajax遠(yuǎn)程獲取某網(wǎng)頁數(shù)據(jù)時(shí)經(jīng)常遇見 如果目標(biāo)頁面是XML,就好辦了,實(shí)用XMLDOM可以很輕松完成任務(wù)。2010-11-11Canvas?drawImage方法實(shí)現(xiàn)圖片壓縮詳解
這篇文章主要為大家介紹了Canvas?drawImage方法實(shí)現(xiàn)圖片壓縮詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11JavaScript利用Date實(shí)現(xiàn)簡單的倒計(jì)時(shí)實(shí)例
在日常開發(fā)的時(shí)候經(jīng)常遇到關(guān)于倒計(jì)時(shí)的需求,下面這篇文章就給主要介紹了JavaScript利用Date實(shí)現(xiàn)倒計(jì)時(shí)效果的方法示例,文中主要實(shí)現(xiàn)了倒計(jì)時(shí)和倒計(jì)時(shí)結(jié)束搶購的按鈕才可以被點(diǎn)擊的效果,有需要的朋友可以參考借鑒。2017-01-01JavaScript函數(shù)的一些注意要點(diǎn)小結(jié)及js匿名函數(shù)
本文給大家總結(jié)了javascript函數(shù)的一些注意要點(diǎn)及js匿名函數(shù),主要知識點(diǎn)有:函數(shù)的基本語法、函數(shù)的參數(shù)、函數(shù)的重載相關(guān)知識,對本文感興趣的朋友一起學(xué)習(xí)吧2015-11-11