为了账号安全,请及时绑定邮箱和手机立即绑定

【金秋打卡】第16天 vue基础入门(下)| 2-13 Provide,Inject,模版 Ref 的用法

标签:
Vue.js

这篇文章可以入选评委评选的最佳手记吗?期待ing…

模块名
描述
课程名称
前端工程师2022版
课程章节
vue基础入门(下)
打卡知识进程
知识进程:16 / 21
(15) 2-12 生命周期函数的新写法
(16) 2-13 Provide,Inject,模版 Ref 的用法
X(17)3-2 VueCLI 的使用和单文件组件(1)
X(18)3-3 VueCLI 的使用和单文件组件(2)
X(19) 3-4 使用单文件组件编写 TodoList
X(20)3-5 Vue-Router 路由的理解和使用(1)
X(21)3-6 Vue-Router 路由的理解和使用(2)
主讲老师
Dell
学习开始时间
2022.11.09 21:41
学习结束时间
2022.11.09 22:59
总计时
78 min
课程收获

我们始终围绕是什么+为什么+怎么用
来输出所学收获
(1)是什么:
Provide,Inject,模版 Ref 的用法,步骤
(2)怎么玩:
写法参考demo示例。
学习感受/感想/领悟(心得)
今日学习时间比前几日都有点长,为什么?

主要内容:
----------------------good start----------------------
在这里面我们去创建一个非常简单的组件,‍‍依然用一个ref ,
我们去创建一个name,等于 dell 这样的一个小的引用就可以了。‍‍
当然我说的 ref指的是如何去操作页面上的 DOM。

然后我们return出 引用 以及对应的 handleClick 方法。‍‍‍‍
接着我再创建一个子组件,
我创建一个全局的‍‍子组件叫做 app.component
在这里面叫做叫child,‍‍它里面我写一个template,就是一个div child,‍‍

然后我们在我的模板里面去用一下 child 的组件,上面的内容我先都删掉,就一个空对象‍‍看起来更加的简单一些:

保存,到页面上我们刷新,没问题,child展示出来了:

接下来我们说‍‍在之前我们的代码里,如果父子组件做传值的时候,可以用props这样的传值对不对?‍‍现在依然可以这么传。‍‍
之前我们讲过一个语法叫做provide的这样的语法,

这里面我们可以向子组件去提供我们想提供的数据,‍‍但是在composition API里面,
如果我们想去做provide的这样的一个数据的提供,该怎么去提供呢?‍‍

在composition API里面,在setup函数里面,‍‍我可以去引入 provide 方法,从 Vue 里面去引,‍‍

然后我们可以通过provide向子组件或者说孙子组件多层的‍‍子组件去传递各种各样的内容,
比如说我传递一个叫做‍‍ hello这样的或者说叫 name 这样的数据,它的值叫做dell,‍‍

前面是它的key值,后面是它的value。

我提供了这样的数据给子组件,‍‍当然你这块也可以给一个对象,比如说这块先提供一个字符串,子组件怎么去接收它?

我们可以在这里也写一个setup函数:

子组件如果想接收你传递过来的数据的话,这里‍‍ provide 对应的 是inject这样的方法,‍‍
我要用它的话,我就需要通过inject方法把这个数据拿到,我就可以const name等于inject,‍‍拿谁?
拿name这样的数据。‍‍

后面其实还可以跟一个参数,比如说叫hello,‍‍它指的是如果你拿 name 拿不到的话,它默认值就是hello,
所以这块我先不给默认值了,直接取name:

取完之后在我的组件里面,我就可以用这个插值表达式来使用这个name,当然你别忘了要return出去:

我们看父组件传递下来的 name 是不是能在子组件里去获取的:

没有任何的问题,dell 就能获取到了。‍‍

我们之前讲的默认值 hello我们可以写一下:

如果你上面不传这个name的话:

我们刷新它就会展示hello:

当你传 name 的时候:

它就会展示 dell:

所以这是默认值的概念。‍‍

当然‍‍有的时候我希望比如说因为这只是一个父子传值,实际上 provide 的适合的场景是一个‍‍多层的数据传递。

假设我们现在‍‍ 父组件或者说最顶级的组件提供了一个name等于dell,
然后底下的组件‍‍去获取了 name,
然后去展示它,

假设我子组件最底下组件想改变 name 值,那么该怎么去改变了?‍‍

我们说‍‍Vue 的数据尽量是一个单向数据流的概念,也就是父组件向子组件传递数据,(代码写注释)

子组件‍‍不要去改变父组件传递过来的这些内容。‍‍

子组件如果想改变 name 的数据,你要调父组件的方法,‍‍在父组件里面去修改这个数据,怎么理解?

谁提供的数据 就在哪里去修改这个数据,‍‍(只是为了好玩)

比如说‍‍父组件提供的数据,那么我对数据的修改就都要在父组件里来做,‍‍
而子组件使用这个数据,如果你想改这个数据不能在它里面去改,而需要告诉父组件让父组件去改才可以。‍‍

这是一个数据修改的职责的问题,以及一个单向数据流的概念。‍‍

如果说我父组件提供的数据 子组件想去修改的话,‍‍我怎么去修改?

不能修改,必须让父组件去修改它,有什么办法?

其实我们可以这样去做,首先‍‍我把 dell 改成一个ref 形式的数据,这样的话我们能看到效果,

所以这块我们用 ref 去‍‍去生成 name的值,

这块我获取到 name,‍‍然后我在return name,
然后直接用 name 就行了,

这块我们不用加 name点value,因为ta会帮我们自动的转化,我们先刷一下看一下效果:

如果点击子组件的内容的时候,我希望改变 name 的值,‍‍我可以写个 handleClick 方法,

子组件被点击了,然后我写一个consthandleClick,‍‍我怎么改变 name?

大家可能去想我直接name点value等于lee是不是就可以了?‍‍

可以的,刷新点一下:

有点问题,哦,是没有导出出去‍‍:

保存,点击dell能改成lee:

但是我说了如果这么写不太合适,因为父组件的数据‍‍你在子组件里直接修改它不是一个好的行为,不符合单项数据流的要求,‍‍
尽量的让父组件去修改它,我们怎么办?‍‍

我们这样去做,在父组件里面我们再定一个方法,‍‍provide叫做一个 changeName 这样的方法,它其实就是一个什么?

它是一个‍‍箭头函数就可以了。

干了一件什么事?
当然它会接收一个参数,你传递过来的 value,‍‍
然后我定义一下:

然后你改变的时候改变的是name 点 value等于value,‍‍
我向子组件提供了一个叫 changeName 这样的方法去帮助‍‍它去改变 name 的值,

那么这样的话在子组件里面我们就这么去写,‍‍const changeName 等于inject changeName,‍‍

然后如果子组件我想改变这个数据的话,我就不要直接去改,‍‍我调父组件传递过来的方法让父组件去改,

比如说你想给它改成 lee,你这么去写是更加合适的一种写法:

我们到页面上刷新,点击dell它能够变成lee:

这个时候子组件想去改变 inject 过来的name的时候,它就不是自己去改了,‍‍
而是调用父组件传递过来的方法去改它,那这样的话是更合理的。‍‍

name的定义以及修改最终都在父组件里完成,这是一个合理的单项数据流的写法,
代码维护起来‍‍定义错误的时候都会更简单一些,‍‍

但是如果这么写,其实还是避免不了一个问题,有的时候不会写代码的人可能会在这里通过name点value‍‍去直接改变你父组件传递过来的内容:

有没有办法去避免这个问题?
有的有的,我们可以这么去写。‍‍

有一个叫做 readonly 这样的API,
然后我们可以通过‍‍ readonly 把 name 做一个封装之后再传给子组件:

这样的话你传递给子组件的 name 就没法直接去修改它了,

比如说在这儿我之前想写怎么写?‍‍我写的是拿到name点value去改它的值 value等于lee:

保存再刷新‍‍,点 dell 它就会提示说什么?

说 target 是一个 readonly 的内容,你不能修改它,‍‍这样的话就把它限制住了。‍‍

而如果你用下面的方式去改它的话,‍‍这样的话是没问题的:

为什么?
因为你调父组件传过来的 changeName 的时候,你改的是name 这个数据,并不是‍‍包装过后的readonly的数据:

所以name数据它不是readonly,它是直接可以改的,‍‍通过这种方式我们可以约束住这种单向数据流的概念,‍‍
子组件不能改变父组件传递过来的数据,‍‍而父组件是自己可以改变自身的数据的,

刷一下再来看一下:

点击 dell 能改变成 lee,没有任何的问题:

这就是如何使用provide和‍‍ inject这两个知识点。‍‍

接着我们来讲最后一个知识点叫做 dom 的 ref,‍‍什么意思?

比如说我这就是一个div,‍‍它里面展示一个hello world,
这块 return 一个空,‍‍如果我在我的 setup函数里面想去获取 dom,

比如说这里面我们记得有一个生命周期函数叫做on‍‍Mounted ,

我们想在生命周期函数里面‍‍去获取dom,等页面加载完成之后去获取一下 div对应的 dom节点,该怎么做呢?‍‍

我们可以在这加一个 ref,比如说等于hello‍‍:

在 composition API 里面,我们如果想拿到‍‍这个 ref 等于hello的这样的 div dom 节点 我们该怎么做?

其实这块有一个固定的语法,
首先你要定一个const hello,跟 ref 的名字相等的这样的一个变量,它等于 ref null,‍‍这是一个固定的写法:

你就创建一个空的 ref 这样响应式的对象,然后你把它导出出去,‍‍
然后 ref 里面的 hello 恰好和你导出 hello 对应的上:

这个时候你 hello 变量实际上保存的就是 div 对应的元素的 dom 引用了,‍‍

我们可以在 mounted 里面试验一下,打印一下 hello:

刷新一下,我们可以看到它说 ref 没有定义:

这块我要在上面const ref 等于 Vue 引一下:

保存,再刷新:

ta又会报一个错误,我们看说onMounted is not defined,所以这块大家一定要注意一下:

hello world:

然后ta现在拿到的这个东西实际上就是我们的dom节点,
我们可以去‍‍调用一下它的innerHtml:

打印一下看一下结果刷新‍‍:

说是 undefined,

我们看一下问题在哪,是不是打印hello点value:

因为它是一个 ref 的引用,没问题:

它的 dom 节点其实存在的是 ref 响应式引用的 value 里面来。‍‍

所以通过这样的一个语法,我们就可以获取到‍‍模板里面对应的内容的到元素节点了,怎么获取?

首先‍‍你这里要定一个ref:

当然
**此 ref **
和上面的
**彼ref **
是完全不一样的东西,

此 ref 指的是‍‍你要获取 dom 节点的引用,
而上面这个 彼ref指 的是生成一个响应式的引用,不是一个东西,‍‍只不过这两个语法我们配套使用才能获取到 dom 节点,
怎么配合?

首先你定一个ref等于一个值:

然后你在 setup函数里面去定一个与这个名字一致的这样的一个常量,让它等于一个空的‍‍ ref 响应式引用,然后你再把它倒出去就行了:

这个时候在onMounted 这样生命周期函数里,
你通过‍‍ hello 这个响应式引用的value值就可以获取到你想获取的 div元素节点的真实的dom节点了。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消