1. 学习内容:
(1) v-once、ref、provide、inject

示例代码:

【Vue】 v-once、ref、provide、inject_ide

假如我在div标签加上v-once指令,示例代码:

【Vue】 v-once、ref、provide、inject_ide_02

执行效果:

【Vue】 v-once、ref、provide、inject_数据_03

代码解读:

点击 1 你会发现它已经不会加 1 了,但是如果我们看​​vm.$data.count​​的话,‍‍结果已经变成11了,但是页面展示的还是1:

【Vue】 v-once、ref、provide、inject_ide_04

所以 v-once 它的意思是什么?它的意思是这样的,‍‍你的 div 标签只被渲染一次,后面即便数据发生变化了,你也不要再渲染了,你只渲染一次就行了。‍‍所以v-once是这样的一个指令,

所以如果你想让某一个标签只渲染一次的话,用它就可以了。‍‍

我们接着学习 【ref】 reference 引用 这样的概念,来看这样的代码示例:

【Vue】 v-once、ref、provide、inject_前端_05

代码解读:

ref 是干什么用的?
有的时候比如说‍‍我是可以通过数据来控制 dom 的一些展示的,但是偶尔会有这样的情况,‍‍什么情况?
比如说你做一些轮播效果的时候,你必须得怎么样?‍‍
在获取到这个模板对应的标签的真正的dom节点。‍‍

但如果你想获取到真正的 dom 节点的话,‍‍以前的那些语法是没有办法获取到的。比如说我在 mounted 里面,页面已经加载完成了,一定要记得必须在mounted 里面写,‍‍因为只有页面都已经挂载完成之后才存在 dom 这个概念,否则你比如说 create 这个时候,‍‍其实它没有把这些标签挂载到元素上,你根本就没法获取 dom。‍‍所以如果想要获取dom,

首先你尽量在 mounted 里面去写一些代码,如果获取dom我们怎么获取?‍‍
你想获取哪个dpm就在哪个dom节点上加一个ref,给它一个名字,之后你在 mounted 里面等待挂载结束之后,‍‍
就可以通过​​​this.$refs.count​​​ 来实现,this点 点的是对应的 ref的名字来获取到 dom节点了,‍‍
执行结果:

【Vue】 v-once、ref、provide、inject_vue.js_06

它会报一个错说我们的模板上语法有点问题,我们看一下 div标签没有闭合上,修改如下:

【Vue】 v-once、ref、provide、inject_vue.js_07

再看效果:

【Vue】 v-once、ref、provide、inject_前端_08

现在能够把 dom 标签给打印出来,所以这就是 ref 的使用场景
比如说如果页面加载完成了,‍‍渲染也完成了,挂载好了之后你必须得操作dom,比如拿到count之后,你让它的innerHTML等于‍‍ hello,
你必须要做这些操作的时候,那么你要获取到dom节点的时候,可以用ref这种引用的方式去获取到‍‍对应的dom节点来做一些操作。‍‍

ref 实际上它是获取什么?‍‍实际上是获取dom节点用的一个语法。【但是我不建议大家过多的使用dom的操作,‍‍除非逼不得已的情况下才去操作dom】

它除了获取节点之外,它还可以获取什么?它还可以获取组件的引用。

代码示例:

【Vue】 v-once、ref、provide、inject_ide_09

代码解读:

在第24行我直接用common-item,‍‍然后我在common-item里面定义一个方法,‍‍比如说methods‍‍叫sayHello,
它干了件什么事情?
alert hello。‍‍

在父组件里面我们可以给子组件加一个ref等于‍‍比如说common给它一个引用,那么等到加载完成之后,我们可以去打印一下 this点​​$refs​​点comment,

如果获取到自组件的引用之后,我们在父组件里就可以调用子组件里面的方法了。‍‍
效果:

【Vue】 v-once、ref、provide、inject_数据_10

它会弹出一个 hello。【alert】

所以你也可以通过ref这种语法获取到子组件或者子的Vue实例的这样的引用,‍‍通过引用再去调用子组件的一些方法。

所以ref实际上是获取 dom 节点或者组件引用的一个语法。Ok这么去写就可以了。‍‍

接着我们再学习 provide 和 inject,‍‍ provide 和 inject是帮助我们做多级组件传值的一个语法,来看代码示例:

【Vue】 v-once、ref、provide、inject_ide_11

代码解读:【耐心看完】

比如说 data 里面有一个count,值为1,然后我调一个child,把属性传给子组件,【第22行】怎么传?

我要count等于count传下来,【第22行】

子组件我叫做child,‍‍然后它怎么接?
它要props接受count参数,然后在这里用 count参数,

假设组件还有子组件,下面孙子组件也需要用count,那得怎么做呢?‍‍

比如说三层传递我得再写一个组件叫child-child,然后【第29行】这里我要调用 child-child 两层的一个子组件,我怎么把 count 再传下去?

我要count等于冒号count,然后【第33行】在这里面再接收count,把 count打印出来【第34行】。‍‍

也就是说如果父组件传给子组件的子组件的时候,‍‍也就父组件传给孙子组件的时候,那要怎么把这个数据一层层的传下去?

首先要通过props把组件传给子组件,‍‍再通过props把子组件的属性再传给孙子组件,就这样层层的传递,‍‍这才三层,比如说再有一层child-child-child ,是不是你又要中间通过plus传递一层?‍‍‍‍

如果涉及到一个属性,要经过很多层的传递的话,现在这种写法实际上就比较冗余比较麻烦了,‍‍传递的过程实在是太麻烦了。‍‍

你可以想象如果十几层的话要传死你对不对?
为了解决这个问题,我们可以用一个新的语法,我们叫做provide和inject,我们可以怎么做?
示例代码:

【Vue】 v-once、ref、provide、inject_前端_12

代码解读:

首先在这里我们写一个provide,‍‍【第20行】然后我把这个可以传个 1,
比如说现在你要给子组件传的就是 1,我通过provide里面写一个​​​count:1​​,

子组件就没有必要再去取 count了,没必要像下面这么写:

【Vue】 v-once、ref、provide、inject_vue.js_13

因为它直接要传给孙子组件,那不必一层层的传,‍‍子组件用不到 count,它就不去传递,也不取这个数据就好了。‍‍

但孙子组件想要用count,‍‍这个时候它怎么能用到父组件里面的 count?

它需要在这里写一个inject跟一个数组:【第35行】

【Vue】 v-once、ref、provide、inject_前端_14

父组件定一个数据,‍‍子组件中间不需要帮它层层的传递,孙子组件只要inject去注入 count就可以直接用了。‍‍

所以如果你涉及多层组件的传值的话,可以考虑用provide和inject的搭配的语法来使用,‍‍provide提供数据,inject直接跨越多层组件来使用就行了。‍‍

在这里我如果想把data里面的数据传给孙子组件,怎么做?

这个东西如果是数据里面的东西的话,‍‍【第17行】
不能通过这样的语法来传递:

【Vue】 v-once、ref、provide、inject_vue.js_15

你要怎么传递?‍‍

示例代码:

【Vue】 v-once、ref、provide、inject_前端_16

你这里要写一个箭头函数,或者说你要把provide变成一个函数,【第20行】

然后我要return一个对象,在这里面我写一个count是 this点count才可以。‍‍【第21-22行】

其实它还有一个问题,‍‍比如说现在我把 count 传给孙子组件,这孙子组件直接去用count展示count,

代码示例:

【Vue】 v-once、ref、provide、inject_数据_17

这里比如说我有一个按钮button,叫做Add增加,
然后绑定click事件等于count加等于1,‍‍每次点击让 count加一,

我们的理解是count变化了,是不是provide里面的 count 就会跟着变化,‍‍然后下面孙子组件展示的内容就会跟着变化?

点击 Add,其实这个数据展示并不会发生变化:

【Vue】 v-once、ref、provide、inject_前端_18

这是什么原因呢?‍‍
是因为这种语法写 provide提供这种数据给孙子组件的话,它是一次性的,‍‍它不是一个响应式的双向绑定的这样的一个数据提供的方式,上面的数据改变了,‍‍它不会感知到 this点count的改变 重新给孙子组件传,

所以孙子组件拿到的永远是你第一次传递的这个值,‍‍有没有办法解决这个问题?

后面会再补充这块的内容。