博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用ES6的class模仿Vue写一个双向绑定
阅读量:6210 次
发布时间:2019-06-21

本文共 6001 字,大约阅读时间需要 20 分钟。

原文地址:

最终效果如下:

image

构造器(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_\-]+) *\}}/gthis.$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)

数据变化之后更新视图

_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()                }            }        })    })}

使用

您输入的是:{
{text1}}+{
{text2}}+{
{text3}}

您选择了:{
{select}}

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})) }) }}

转载地址:http://oxdja.baihongyu.com/

你可能感兴趣的文章
java路径Java开发中获得非Web项目的当前项目路径
查看>>
【工具使用系列】关于 MATLAB 遗传算法与直接搜索工具箱,你需要知道的事
查看>>
Kali-linux Arpspoof工具
查看>>
PDF文档页面如何重新排版?
查看>>
基于http协议使用protobuf进行前后端交互
查看>>
bash腳本編程之三 条件判断及算数运算
查看>>
php cookie
查看>>
linux下redis安装
查看>>
弃 Java 而使用 Kotlin 的你后悔了吗?| kotlin将会是最好的开发语言
查看>>
JavaScript 数据类型
查看>>
量子通信和大数据最有市场突破前景
查看>>
StringBuilder用法小结
查看>>
对‘初学者应该选择哪种编程语言’的回答——计算机达人成长之路(38)
查看>>
如何申请开通微信多客服功能
查看>>
Sr_C++_Engineer_(LBS_Engine@Global Map Dept.)
查看>>
非监督学习算法:异常检测
查看>>
《OSPF和IS-IS详解》一2.7 BGP-IGP的路由交换
查看>>
App开发中甲乙方冲突会闹出啥后果?H5 APP 开发可以改变现状吗
查看>>
python知识点总结---函数
查看>>
jquery的checkbox,radio,select等方法总结
查看>>