#夏日挑战赛# OpenHarmony基于JS开发的VM实例的一点应用 原创 精华
前言
上回我们讲过几个危险的方法,所以,现在拿来单独讲一讲,不过这几个方法配合起来玩还是挺有意思的,理论上,你可以通过这几个方法,在任意一个组件操作所有的界面,是不是很棒?是不是很腻害?(ps:如果你真得用这种方式开发,可能出问题的时候,需要你和代码有一个能跑就行)-|·_·|——
获取VM实例方法
页面结构
每个节点就是一个页面组件,每个节点就是一个vm实例
VM实例是怎么样的?
我们将它遍历输出的结果如下图,
从上面的图中,我们可以看出,有很多熟悉的VM实例方法和属性还有自定义的方法
入口文件是啥?
如上图,在预览器中的entry
的路径,此时我们的入口文件为test2
,如果想切换入口文件,就去文件目录
选择想要切换成入口文件的文件,然后点击预览器中的刷新按钮,即可切换
$root
用法 this.$root()
无参数
获取根VM实例,这跟根vm实例和选择的入口文件有关。例如,上图页面结构图,我们选择得入口文件是test2页面
,在test2页面
和test3组件
分别输出他们的$root
中的data数据
从上图中我们可以看出,当前页面就是入口文件时也就是最顶级VM实例时,获取到的$root
就是当前的VM实例,当在任意一个组件中获取$root
时都可以拿到当前的根实例。
当然我们的入口文件改成test1
时,得到的结果如下图
$parent
用法this.$parent()
无参数
获取父组件的VM实例,当前组件为入口文件时也就是最顶级VM实例,使用this.$parent()
,就会得到以下结果,基本都是内部的的属性,例如在test1组件获取this.$parent
我们分别在test2和test3组件获取他的$parent
, VM实例的data结果如下
$child
用法this.$child("需要获取的自定义子组件的ID值")
有参数 id
获取自定义的组件的VM实例,需要给导入的自定义组件设置id属性,我们分别在test1和test2获取自定义组件test2和test3组件
<!-- 当前组件,test1组件 -->
<div style="width: 100%;height: 40%;" >
<test2 id="r" num="{{num}}">
</test2>
</div>
<!-- 当前组件,test2组件 -->
<div class="container" @click="dd" id="gg" >
<test3 ref="test3" id='ww'>
</test3>
</div>
分别使用this.$child('r').__data
和this.$child('ww').__data
得到的结果如下
VM实例的使用
正常的组件通信
一般我们开发时,组件之间的通信是有迹可循的,也是符合逻辑的,通信图如下
使用VM实例通信,乃至操作
但是,一旦我们开发时组件之间的通信或者跨组件操作,使用通过VM实例的话,那将会对后期维护很麻烦,甚至出BUG你都找破头,你永远不知道会在那个组件突然冒出来操作一下其他组件,如下图
上面这个图才一共五个节点,就已经这么乱了,如果几十上百个,估计得炸,所以,这种玩法只适合自己写的一些小项目或者遇到一些没法解决的问题,迫不得已才使用。
或许还可以这样玩
每个节点都可通过一个中心调度器,在中心调度器中对所有的组件进行统一操作,en…感觉…反正也就是个想法,谁有空可以玩玩
VM实例的跨组件操作
接下来,我们将在test3组件操作test5组件
具体流程 test3 → test1 → test4 → test5
在引用test4和test5时,我们分别给他们设置了id为test4,test5
//test5 组件
export default {
data: {
title: "我是test5"
},
useing(s){
console.log(`${this.title},${s}正在使用我的useing方法 `)
}
}
// test3组件
onLayoutReady(){
const node = this.$root().$child('test4').$child("test5")
node.useing("test3")
console.log(`原test5的title值 ${node.__data.title}`)
node.__data.title= '我被修改了'
console.log(`改后的test5的title值, ${node.__data.title}`);
},
输出的结果如下
用起来感觉如何,写到这里,就想起前面dom上说过自定义的组件事件阻塞没有效果,我们也可以利用vm实例来解决
阻止事件冒泡
起因
由于dom中有一个事件冒泡机制,如下图,子组件test3触发click事件,那么,其父组件test2,以及test2的父组件test1也同样因为事件冒泡触发click事件
stopPropagation() 和 currentTarget 结果不符合预期
在上次写到的stopPropagation()
应该是用来阻止事件冒泡的方法,但是并无效果,使用后还是继续冒泡,不知道你们的设备上是不是这样,我在预览器上就这样,没有板子测试,currentTarget
也不符合预期效果,没有办法获取事件源的dom,也无法就处理事件冒泡,那么冒泡该如何绕开
通过移除事件和添加事件
在同一个页面组件下的父子元素事件冒泡
<div class="container" @click="dd" id="gg" >
<div id="e" ref="test2" style="height: 222px; height:300px ;background-color: aqua;" @click="c">
<text class="title" >
{{title}}, test1的子组件
test1传过来的num
</text>
</div>
</div>
dd(e){
console.log("父元素click事件触发")
},
c(e){
console.log('子点击')
},
我们可以通过dom的方法 removeEvent
和 addEvent
dd(e){
console.log("父元素click事件触发")
},
c(e){
console.log('子点击')
const d = this.dd
const node = this.$element('gg');
node.removeEvent('click')
setTimeout(()=>{
node.addEvent('click',d)
})
},
通过这样移除事件回调函数后再添加,我们可以模拟一个类似于一个阻塞事件冒泡,但是还是会继续冒泡,那么子组件冒泡到父组件又怎么解决?
处理跨组件冒泡
上面我们提到的VM实例操作终于有用了,我们可以通过获取到父组件注册的事件回调方法,然后去取消父组件的
我们给test1组件设置一个id = “test1” ,click事件回调函数为cc
<div class="container" id="test1" @click="cc" data-bb="{{title1}}}" >
<div style="width: 100%;height: 10%; display: flex; flex-direction: column;" >
<text class="title" >
这是父组件{{title}}
</text>
</div>
</div>
在父组件test1的click事件回调方法
cc(e){
console.log('我是test1,click事件触发的方法,cc')
},
test2组件click事件的回调函数
c(e){
console.log('子点击')
const d = this.dd
const node = this.$element('gg');
node.removeEvent('click')
setTimeout(()=>{
node.addEvent('click',d)
})
},
事件冒泡的结果图如下
处理跨组件事件冒泡
我们可以通过获取vm实例,再通过获取触发click事件的元素,然后移除和添加事件
c(e){
console.log('子点击')
const node = this.$parent();
const fun = node.cc;
const dom = node.$element('test1')
dom.removeEvent('click')
setTimeout(()=>{
dom.addEvent('click',fun)
})
}
结果如下
这样子可以避免触发父组件的点击事件
最后
获取VM实例的这几个方法还是老规矩,不推荐使用,平时玩玩还可以,上述的事件冒泡的处理也莫得办法,官方给的api接口我用竟然没效果,不知道你们用的是咋样
这是我学过的最复杂的冒泡,VM既然如此复杂,他的具体应用场景是哪里呢?
可能最多是组件通信,但就是因为复杂,他可以用更加友好的方式被替代,有的时候想绕过一些东西的时候也可以使用