学习过VueJS的小伙伴都知道,Vue本身有内置的指令v-if和v-show。两者本身都可以控制节点的隐藏和显示,只是各自实现的原理不一样。下面尝试实现一遍类似,简版的v-show和v-if。
首先创建一个index.html文件,里面创建一个id为app的div元素,里面存放相应的子元素。
<div id="app">
<div class="box-wrapper">
<div class="box box1" v-if="boxShow1">BOX 1</div>
<div class="box box2" v-show="boxShow2">BOX 2</div>
</div>
<button @click="showBox1">BOX 1</button>
<button @click="showBox2">BOX 2</button>
</div>
给元素命令class类名,box1绑定v-if,box2绑定v-show,按钮Box1和按钮Box2分别绑定showBox1和showBox2方法控制box1和box2的显示和隐藏。css样式方面省略介绍。效果图如下。
在index.html文件的相同路径下创建一个index.js文件,并在index.html文件下引入。在index.html文件下的script写相应的逻辑代码。
<script>
new mVue({
el: #app,
data() {
return {
boxShow1: false,
boxShow2: false
}
},
methods: {
showBox1() {
this.boxShow1 = !this.boxShow1
},
showBox2() {
this.boxShow2 = !this.boxShow2
}
}
})
<script>
到这里或多或少有点疑惑,mVue到底是什么?其实mVue的主要核心在index.js。
用过VueJS都知道,v-show在html元素上是通过控制display来显示隐藏的,而v-if在html元素上通过来占位。
class mVue{
constructor(options) {
this.el = document.querySelector(el)
this.data = typeof(this.options.data) === 'function' ? options.call(this) : options.data
this.methods = options.methods
this.showPool = new Map()
this.eventPool = new Map()
this.init()
}
}
showPool接收的是一个map的数据结构,key为节点类型的dom,value为一个对象,字段type的值为if或show,字段show的值为true或false,字段data为绑定的数据。
showPool接收的也是一个map的数据结构,key为节点类型的dom,value为绑定的方法。
为什么选择map作为数据结构?因为map的key可以是任意类型
init() {
this.initData() // 代理数据与数据劫持
this.initDom() // 初始化Dom
this.initView() // 初始化视图
this.initEvent() // 事件处理函数的绑定
}
initData() {
for (let key in this.data) {
Object.defineProperty(this, key, {
get() {
return this.data[key]
},
set(newValue) {
this.data[key] = newValue
this.domChange(key, this.showPool)
}
}
}
}
initDom(el) {
const _childNodes = el.childNodes
if (!childNodes.length) return
_childNodes.forEach(dom => {
if (dom.NodeTye === 1) {
const vIf = dom.getAttribute('v-if')
const vShow = dom.getAttribute('v-show')
const vEvent = dom.getAttribute('@click')
if (vIf) {
this.showPool.set(dom, {
type: 'if',
show: this.data[vIf],
data: vIf
})
} else if (vShow) {
this.showPool.set(dom, {
show: this.data[vShow],
data: vShow
})
if (vEvent) {
this.eventPool.set(dom, this.methods[vEvent])
}
}
this.initDom(dom)
})
}
initView(showPool) {
this.domChange(null, showPool)
}
domChange(data, showPool) {
if (!data) {
for (let [k, v] of showPool) {
switch (v.type)
case: 'if':
v.comment = document.createComment(`v-if`)
!v.show && k.parentNode.replace(v.comment, k)
break
case 'show':
!show && (k.style.display = 'none')
break
default:
break
}
}
return
}
for (let [k, v] of showPool) {
if (v.data === data) {
switch (v.type) {
case 'if':
v.show ? k.parentNode.replaceChild(v.comment, k)
: v.comment.parentNode.replaceChild(k, v.comment)
v.show = !v.show
break
case 'show':
v.show ? (k.style.display = 'none')
: (k.style.display = 'block')
v.show = !v.show
break
default:
break
}
}
}
}
initEvent(eventPool) {
for (let [k, v] of eventPool) {
k.addEventListener('click', v.bind(this), false)
}
}
boxShow1为false的情况
boxShow2为false的情况
boxShow1和boxShow2都为true的情况下,元素的情况
上面就是大体简单的实现情况。
完结,撒花.jpeg