🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] >[success] # Provide,Inject,模版 Ref 的用法 本章将讲解 **Provide、Inject、Ref** 在 **composition API** 中如何使用,但是我们说的这个**Ref** ,是 **获取dom元素** 的那个**Ref** ,不是 **定义基本类型响应式数据** 时用的那个 **Ref** 。 >[success] ## Provide Inject 的用法 **composition API** 解决了 **Provide Inject** 数据响应式的问题,下面看一下在 **composition API** 中如何使用 **Provide Inject** ,如下代码: 1. **inject 默认值** **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Provide、Inject的用法</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // 父组件 const app = Vue.createApp({ setup(){ // 引入 provide const { provide } = Vue; // 向【后代】传递数据(格式:provide(属性名,值)) provide('name', 'dell') return { } }, template: ` <div> <child /> </div> ` }) // 子组件 app.component('child', { setup(){ // 引入 inject const { inject } = Vue; // 获取【祖先】组件传的数据(格式:inject('属性名', '默认值'),如果 provide 没有 name 就使用默认值小明) const name = inject('name', '小明') // 返回数据 return { name } }, template: '<div>{{ name }}</div>' }) // 挂载 const vm = app.mount('#root') </script> </html> ~~~ 上面代码中 **inject** 如果获取不到值,默认赋值为 **inject** 的第 **2** 个参数(**默认值** )。 2. **后代修改祖先值** **Vue** 是 **单向数据流** 的概念,**子组件** 不可以 **修改 父组件** 传入的 **数据** 。那使用 **Provide、Inject** 时,**后代组件** 想修改 **祖先组件 Provide 传过来的值** ,该怎么修改呢? 2.1 **错误示范** 下面这种写法,虽然也可以修改数据,但是 **不符合单向数据流的要求** **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Provide、Inject的用法</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // 父组件 const app = Vue.createApp({ setup(){ // 引入 provide const { provide, ref } = Vue; // 向【后代】传递数据 provide('name', ref('dell')) return { } }, template: ` <div> <child /> </div> ` }) // 子组件 app.component('child', { setup(){ // 引入 inject const { inject } = Vue; // 获取【祖先】组件传的数据 const name = inject('name') const handleClick = () => { name.value = '小明' } // 返回数据 return { name, handleClick } }, template: '<div @click="handleClick">{{ name }}</div>' }) // 挂载 const vm = app.mount('#root') </script> </html> ~~~ 2.2 **正确写法** **后代组件需要调用祖先组件的方法,然后在祖先组件中去修改数据** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Provide、Inject的用法</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // 父组件 const app = Vue.createApp({ setup(){ // 引入 provide const { provide, ref } = Vue; const name = ref('dell') // 向【后代】传递数据 provide('name', name) // 向【后代】传递 changeName 方法 provide('changeName', (value) => { name.value = value }) return { } }, template: ` <div> <child /> </div> ` }) // 子组件 app.component('child', { setup(){ // 引入 inject const { inject } = Vue; // 获取【祖先】组件传的数据 const name = inject('name') const changeName = inject('changeName') const handleClick = () => { changeName('小明') } // 返回数据 return { name, handleClick } }, template: '<div @click="handleClick">{{ name }}</div>' }) // 挂载 const vm = app.mount('#root') </script> </html> ~~~ 3. **搭配使用 readonly ,防止单向数据流被后代组件篡改** 有许多时候,许多人不懂得 **单向数据流的概念** ,还是会在 **后代组件** 中去修改 **祖先组件** 传入的值,为了解决这个问题,可以使用 **readonly** 把参数变成只读,来解决这个问题,代码如下: **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Provide、Inject的用法</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> // 父组件 const app = Vue.createApp({ setup(){ // 引入 provide const { provide, ref, readonly } = Vue; const name = ref('dell') // 向【后代】传递数据 provide('name', readonly(name)) return { } }, template: ` <div> <child /> </div> ` }) // 子组件 app.component('child', { setup(){ // 引入 inject const { inject } = Vue; // 获取【祖先】组件传的数据 const name = inject('name') const handleClick = () => { name.value = '小明' } // 返回数据 return { name, handleClick } }, template: '<div @click="handleClick">{{ name }}</div>' }) // 挂载 const vm = app.mount('#root') </script> </html> ~~~ >[success] ## Ref 的用法 在 **composition API** 中,我们如何通过 **ref** 获取 **dom** 元素呢? **index.html** ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Ref 的用法</title> <!-- 通过cdn方式引入vue --> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="root"></div> </body> <script> const app = Vue.createApp({ setup(){ const { onMounted, ref } = Vue; // 01. 名字与标签 ref 的名字相等,这是固定写法 const hello = ref(null) onMounted(() => { // 获取 ref 有 hello 的 dom 元素 console.log(hello.value) }) // 02. 导出 hello return { hello } }, // 03. ref 起名为 hello template: ` <div ref="hello">小明</div> ` }) // 挂载 const vm = app.mount('#root') </script> </html> ~~~