Vue3---组件的定义及复用性、局部组件、全局组件、组件间传值及其校验、单项数据流、Non-props属性

95 阅读2分钟

#完整原文地址见简书www.jianshu.com/p/1bc868ff4… #更多完整Vue笔记目录敬请见《前端 Web 笔记 汇总目录(Updating)》



#本文内容提要

  • Vue.createApp()的参数是页面的根组件

  • 自定义的子组件是可以被复用的,且多个复用子组件之间数据相互独立

  • 自定义的【全局子组件】方便快捷,随处可用,但影响性能

  • 定义局部组件

  • 局部组件再例

  • 局部组件语法一重点

  • 全局组件、局部组件比较

  • 父子组件间相互通信的方式

  • 动态参数传参 解决 number转string的问题

  • 传参类型校验

    • 传参类型校验再例【Boolean例】
    • 传参类型校验再例【Function例】【传递函数型参数】
  • props

    • props块的required属性 配置必填效果
    • props块的default属性 配置默认值
    • props块的validator属性 配置参数值大小限制
  • 多个数据 传参时常规写法

  • 使用Object方式优化v-bind传参

  • HTML中,推荐使用 横杠分割法 代替 驼峰命名法

  • 单向数据流的理解

    • 解决方法
    • 单向数据流存在的意义
  • Non-prop 属性

    • 子组件使用inheritAttrs: false属性配置,可以拒绝继承接收 父组件传递过来的属性
    • Non-props 应用场景
    • $attrs修饰符
    • $attrs修饰符 再例
    • $attrs 运用于生命周期方法中

####`Vue.createApp()`的参数是页面的根组件 **`Vue.createApp()`传入的参数,将作为页面的根组件, 似Android的`rootView`:** ``` Hello World! heheheheheheda
``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/88d34e40086a45c0a30e79b752114f80~tplv-k3u1fbpfcp-zoom-1.image)
####自定义的子组件是可以被复用的,且多个复用子组件之间数据相互独立 **如下复用三个``自定义子组件,三个``之间数据相互独立:** ``` ``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6ab372bc8c9a4577ba2915270df542d2~tplv-k3u1fbpfcp-zoom-1.image)
####自定义的【全局子组件】方便快捷,随处可用,但影响性能 **自定义的全局子组件方便快捷,随处可用, 任何地方都可以引用子组件,如下【似Android的Fragment】代码;
但只要使用`.component()`定义了子组件,子组件便挂载在`VueApp`实例上了, 即使不调用该子组件,它也会占用内存和性能:** ``` ``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0ecc10f50b0d45a9b36268e05560d6a8~tplv-k3u1fbpfcp-zoom-1.image)
####定义局部组件 语法: ``` const 局部组件实例名= { data() { return { ... } }, template: ... }

const app = Vue.createApp({ components: { 定义局部组件引用名 : 局部组件实例名}, template: <div> <局部组件引用名/> </div> });

案例代码:
**效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e72a49bb274341f9805fd69c8d44ae3a~tplv-k3u1fbpfcp-zoom-1.image)**
<br>
**如果`局部组件实例名``定义的局部组件引用名` 相同,
则可以直接使用以下的`简写语法`:**
效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3b4e10d1f894451e80ec1a9029adea3f~tplv-k3u1fbpfcp-zoom-1.image)


<br>
####局部组件再例
效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/218965f36cd8498b876efaed4c4156a4~tplv-k3u1fbpfcp-zoom-1.image)

<br>
####局部组件语法一重点
**为了将`局部组件``实例名` 同 普通的js(驼峰命名法)变量区分开来,
推荐使用`首字母大写``驼峰``局部组件``实例名`进行命名,
同时,
Vue代码在`template`中引用`局部组件时`时,
会忽略大小写和杠号 对`components`中定义的组件进行映射;
如下,
`<counter />`忽略了大小写 映射到 `Counter``<heheda-dom />`忽略了横杆号和大小写 映射到 `HehedaDom`:**
效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e18134cd70f3400da451760137bccd46~tplv-k3u1fbpfcp-zoom-1.image)

<br>
####全局组件、局部组件比较
>**全局组件定以后,随处可用,方便快捷,任何地方都可以引用子组件,
但性能不高(定以后 不用时也 挂载并占用内存),
命名建议,小写字母 配合 横线隔开;<br>
局部组件 定义后 需注册才能使用才会占用资源,性能较高,
但使用较麻烦,
>命名建议,大写字母 配合 驼峰命名法;**

<br>
####父子组件间相互通信
**主要是借助`props`的方式:**
Hello World! heheheheheheda
``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/29bf10069b2f4d019870443eb4afc399~tplv-k3u1fbpfcp-zoom-1.image)
####动态参数传参 解决 number转string的问题 静态传参,存在如题问题: ``` ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/df1578c1cbe648989925744569f4f4e6~tplv-k3u1fbpfcp-zoom-1.image)

将数据写在data版块中,借用v-bind 动态传参,解决以上问题:

<script>
    const app = Vue.createApp({
        data() {
            return {
                num : 666
            }
        },
        template: `
        <div><test :content = 'num'></div>`
    });

    app.component('test', {
        props: ['content'],
        template:`<div>{{content}}<br>
            {{typeof content}}</div>`
    })

    const vm = app.mount('#heheApp');
</script>


####传参类型校验 >**传参类型校验支持:String、Boolean、Array、Object、Function、Symbol 等类型;**

关键: 将props位的值,从数组形式换为对象(键值)形式, 键为承接属性,值为期望值类型

<script>
    const app = Vue.createApp({
        data() {
            return {
                num : 666
            }
        },
        template: `
        <div><test :content = 'num' /></div>`
    });

    app.component('test', {
        props: {
            content : String,
        },
        template:`<div>{{content}}<br>
            {{typeof content}}</div>`
    })

    const vm = app.mount('#heheApp');
</script>

如上代码,期望得到一个String类型的参数,却传入一个number类型的参数, 则运行时 会刷出报错警告: 更正入参类型,则不再报错:

<script>
    const app = Vue.createApp({
        data() {
            return {
                num : "666"
            }
        },
        template: `
        <div><test :content = 'num' /></div>`
    });

    app.component('test', {
     ...
    })

    const vm = app.mount('#heheApp');
</script>


####传参类型校验再例【Boolean例】 ``` ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/88afc660916343e99a604097467c17ff~tplv-k3u1fbpfcp-zoom-1.image)
####传参类型校验再例【Function例】【传递函数型参数】 ``` ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5218347e45f1448f873842e4dadec1ec~tplv-k3u1fbpfcp-zoom-1.image) **更正类型【传递函数型参数】:** ``` ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d9b5459b9b554b879c3740a717a4ea53~tplv-k3u1fbpfcp-zoom-1.image)
####`props`块的`required`属性 配置`必填`效果 **`props`块的`required`属性配置`true`时,`要求`对应配置的属性`要传参数`, 没有传参数,则报错;
如下案例,配置了`required`属性为`true`,但没有传参:** ``` ``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6dc30459fd8a4cecb3f953a1f2c821b5~tplv-k3u1fbpfcp-zoom-1.image) **传了参就好起来了:** ``` ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b919af4cbe9d4275bc2667283effa35c~tplv-k3u1fbpfcp-zoom-1.image)
####`props`块的`default`属性 配置`默认值` **如果没有传入参数到子组件,则使用`default`属性 配置的`默认值`:
如下例, 配置默认值86868686886, 不传参数进去子组件:** ``` ``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b32f51067ee04d0cbc779a3e66e586c9~tplv-k3u1fbpfcp-zoom-1.image)
**当然使用`函数返回数据的形式【适用于返回值需要计算的场景】`也是可以的, 如下代码 可以达到同样的效果:** ``` ```
####`props`块的`validator`属性 配置`参数值大小限制` 如下,限制入参必须小于1000,否则报错: ``` ``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/40cfa375b4424ead8c9b1947594b0c86~tplv-k3u1fbpfcp-zoom-1.image) 将入参改为小于1000的数就好起来了: ``` ``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fc62c90868754f27b5433a904c78cc50~tplv-k3u1fbpfcp-zoom-1.image)
####多个数据 传参时常规写法 ``` Hello World! heheheheheheda
``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/07399970b8824027b182cdeeff0e6bce~tplv-k3u1fbpfcp-zoom-1.image)
####使用Object方式优化`v-bind`传参 **`
`一行等价于 `
`;** ``` ``` **此处代码实现的效果跟上面例子是一样的;**
####HTML中,推荐使用 横杠分割法 代替 驼峰命名法 **并且,props承接 横杠分割法字段 时候, 需用对应的 驼峰命名法 字段 去承接,否则无法承接到数据:** ``` ``` **props中 横杠分割法字段参数 无法承接到数据:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b82c6fb3dadd443c9c5acd1420d8ee25~tplv-k3u1fbpfcp-zoom-1.image) 使用对应的 驼峰命名法 字段参数, 承接到 横杠分割法字段:** ``` ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6497263c04d04e1eb16689e06949bcde~tplv-k3u1fbpfcp-zoom-1.image)
####单向数据流的理解 **指 父组件 可以向 子组件 传递数据, 但是 子组件 无法修改 父组件 传递过来的参数变量; 数据只能从 父组件 流向 子组件, 所谓 单向数据流;** ``` ``` 如上代码,运行之后点击组件,会报错提示无法更改值:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1f03cf43ab6f4027a39ec84f07a24b52~tplv-k3u1fbpfcp-zoom-1.image)
####解决方法 **子组件自身准备一个 data字段, 用于拷贝一份父组件传来的参数数据; 后面要借助数据做更新的时候, 使用这个拷贝数据即可:** ``` ``` 效果,可点击实现功能了:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/80c70d46f4c543c8a533c9d42a782ba6~tplv-k3u1fbpfcp-zoom-1.image)
####单向数据流存在的意义 >**如果子组件可以修改父组件的数据,会引发很多逻辑隐患; 如假设父组件 将一个数据 传给若干个子组件, 这时候如果 子组件 可以更改 父组件的字段, 那这时 每一个子组件 都同时对这个 数据 进行修改, 那父组件的数据字段 势必乱套【有点Java的线程安全的意思了】; 所以, 规定数据的单向性,可以避免很多设计逻辑问题 和隐患;**
####父子组件传参,静态传参,父组件中直接写`[属性:值]`,动态传参,则需借助`v-bind`,即`v-bind:属性 = 数据字段`;
####Non-prop 属性 指 **父组件 传数据给 子组件时,子组件 不通过`prop`属性 接收 的属性; 这时,无论传递是否有使用`v-bind`, `父组件`传递的这个`数据字段`,都会成为 `子组件`最外层组件的`属性`;** ``` Hello World! heheheheheheda
``` ![接收父组件`Non-props`属性的子组件最外层组件](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9b2bee5cccdd4b1eb2ceb043145aafe1~tplv-k3u1fbpfcp-zoom-1.image)
####子组件使用`inheritAttrs: false`属性配置,可以拒绝继承接收 父组件传递过来的属性 ``` ``` ![子组件添加`inheritAttrs: false`之后,不再接收父组件传递的属性](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a4bfbe6f6f0b4fea9e3b9c81329a1957~tplv-k3u1fbpfcp-zoom-1.image)
####Non-props 应用场景 **可以轻松传递样式:** ``` ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b726f91b995c4de7a033e2e8eed78431~tplv-k3u1fbpfcp-zoom-1.image)
####$attrs修饰符 >**在之前的笔记 —— [Vue3 | Vue中的诸多花样样式写法 以及 相关规则和技巧](https://www.jianshu.com/p/cdbd2670e075) 中的 【子组件样式 默认跟随 父组件】问题中已经有所提及这个方法了;
当子组件的`template`中有拥有“两个以上最外层组件”时, 父组件传递过来的`Non-props`会失效, 因为没有用`v-bind`指定的属性,只能传给一个`最外层组件`, 当有多个时就会失效;
**


v-bind = $attrs修饰的DOM组件, 会接收父组件传递的所有non-props属性:

<script>
    const app = Vue.createApp({
        template: `
        <div>
            <counter style="color:blue;" msg="heheda" msg2="lueluelue" />
        </div>`
    });

    app.component('counter', {
        template:`
        <div>Counter</div>
        <div v-bind="$attrs">Counter</div>
        <div>Counter</div>
        `
    })

    const vm = app.mount('#heheApp');
</script>


####$attrs再例 >**注意: `v-bind="$attrs"`,`"$attrs"`是一个包含多个值的意义值, 惯例一梭子传给被配置的组件, 没有用`变量`承接,所以要使用`v-bind`承接,不可简写;
但是`:heheda="$attrs.msg"`中,"`$attrs.msg`"是一个`js`表达式,且仅代表一个值, 所以可以用`变量`承接,且可以简写"v-bind";** ``` ``` 效果:![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d458847a48f643faa01ee2ba4626ce34~tplv-k3u1fbpfcp-zoom-1.image)
####$attrs 运用于生命周期方法中 ``` ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/768c461a549e430c9c325db8f6017309~tplv-k3u1fbpfcp-zoom-1.image)