千家信息网

怎么使用ES6的class模仿Vue写一个双向绑定

发表于:2024-11-16 作者:千家信息网编辑
千家信息网最后更新 2024年11月16日,这篇文章主要介绍"怎么使用ES6的class模仿Vue写一个双向绑定"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"怎么使用ES6的class模仿Vue写一个双
千家信息网最后更新 2024年11月16日怎么使用ES6的class模仿Vue写一个双向绑定

这篇文章主要介绍"怎么使用ES6的class模仿Vue写一个双向绑定"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"怎么使用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_\-]+) *\}}/gthis.$el.querySelectorAll("*").forEach(i => { let replaceList = i[xss_clean].match(regExpInner) || (i.hasAttribute('vueID') && i.getAttribute('vueID').match(regExpInner)) if(replaceList) {  if(!i.hasAttribute('vueID')) {   i.setAttribute('vueID', i[xss_clean])  }  i[xss_clean] = i.getAttribute('vueID')  replaceList.forEach(v => {   let key = v.slice(2, v.length - 2)   i[xss_clean] = i[xss_clean].replace(v, this.$data[key])  }) }})

监听器(watcher)

数据变化之后更新视图




您输入的是:{{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[xss_clean].match(regExpInner) || (i.hasAttribute('vueID') && i.getAttribute('vueID').match(regExpInner))   if(replaceList) {    if(!i.hasAttribute('vueID')) {     i.setAttribute('vueID', i[xss_clean])    }    i[xss_clean] = i.getAttribute('vueID')    replaceList.forEach(v => {     let key = v.slice(2, v.length - 2)     i[xss_clean] = i[xss_clean].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}))  }) }}

关于"怎么使用ES6的class模仿Vue写一个双向绑定"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注行业资讯频道,小编每天都会为大家更新不同的知识点。

0