• vuejs之父子组件的通信【props】和【$emit】


    上一篇中谈到了子组件是不能引用父组件或Vue实例挂载的数据。这里Vue实例可看作根组件(root component)。

    问题导入

    但是在开发中,往往一些数据确实需要从上层传递到下层:

    如一个页面中,我们从服务器请求到了很多数据。但这些并非全部应用于一个组件来展示,其中一小部分需要包含的子组件来渲染,(这时我的评价是不如交给子组件去请求需要的数据,各组件请求自己的那份数据不是OK了吗),按照设计者的思路,此时并不会让子组件独自发送一个网络请求的,而是直接让其父组件(大组件)将数据传递给子组件(小组件)。嗯,回过头来想想雀食,一旦下面的子组件过多,所造成的冗余请求对服务器来说,简直是个灾难!

    组件间的关系

    一般来说,组件可以有以下几种关系:

    如上图所示,A 和 B、B 和 C、B 和 D 都是父子关系,C 和 D 是兄弟关系,A 和 C 是隔代关系(可能隔多代)。 

    如何进行父子组件间的数据通信呢?Vue官方提到:

    • 通过props向子组件传递数据。
    • 通过$emit向父组件传递数据。

    真实开发中,Vue实例与子组件的通信和父组件与子组件的通信过程是一样的。

    (注:下面代码示例中,将Vue实例看作父组件,其包含子组件以简化代码)

    props基本用法

    在组件中,使用选项props来声明需要从父级接收到的数据。

    props值的两种写法

    方式一:字符串数组,数组中的字符就是传递时的属性名称(attribute)。

    方式二:对象,里面可以设置传递时的类型,也可以设置默认值等。

    1. <div id="app">
    2. <cpn :cMovies="movies" :cMessage="message">cpn>
    3. div>
    4. <template id="cpn">
    5. <div>
    6. <ul>
    7. <li v-for="(item, index) in cmovies" :key="index">{{item}}li>
    8. ul>
    9. <h2>{{cmessage}}h2>
    10. div>
    11. template>
    12. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
    13. <script>
    14. // 父传子:props
    15. const cpn = {
    16. template: "#cpn",
    17. props: ['cmovies', 'cmessage'],// 数组写法,元素虽然是字符串,但可当做变量
    18. data() {
    19. return {
    20. }
    21. },
    22. methods: {
    23. },
    24. };
    25. const app = new Vue({
    26. el: "#app",
    27. data: {
    28. message: "你好",
    29. movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
    30. },
    31. components: {
    32. cpn
    33. }
    34. })
    35. script>

    使用props数组方式接收父组件data数据时,一定要记住v-bind(或:),否则无法解析,会当成字符串输出。

    Props的类型

    使用props对象方式的话,需要进行类型验证。

    数据类型 可以是下列原生构造函数中的一个:

    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol

    示例:

    1. Vue.component('my-component', {
    2. props: {
    3. // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    4. propA: Number,
    5. // 多个可能的类型
    6. propB: [String, Number],
    7. // 必填的字符串
    8. propC: {
    9. type: String,
    10. required: true
    11. },
    12. // 带有默认值的数字
    13. propD: {
    14. type: Number,
    15. default: 100
    16. },
    17. // 带有默认值的对象
    18. propE: {
    19. type: Object,
    20. // 对象或数组默认值必须从一个工厂函数获取
    21. default: function () {
    22. return { message: 'hello' }
    23. }
    24. },
    25. // 自定义验证函数
    26. propF: {
    27. validator: function (value) {
    28. // 这个值必须匹配下列字符串中的一个
    29. return ['success', 'warning', 'danger'].includes(value)
    30. }
    31. }
    32. }
    33. })

    prop 对象和数组的默认值为什么要为工厂函数的形式返回?原因在这里

    额外的,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。例如,给定下列现成的构造函数:

    1. function Person (firstName, lastName) {
    2. this.firstName = firstName
    3. this.lastName = lastName
    4. }

    你可以使用:

    1. Vue.component('blog-post', {
    2. props: {
    3. author: Person
    4. }
    5. })

    来验证 author prop 的值是否是通过 new Person 创建的。

    Props的驼峰标识

    HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

    1. Vue.component('blog-post', {
    2. // 在 JavaScript 中是 camelCase 的
    3. props: ['postTitle'],
    4. template: '

      {{ postTitle }}

      '
    5. })
    1. <blog-post post-title="hello!">blog-post>

    如果你使用字符串模板,那么这个限制就不存在了。

    示例:

    如果props定义的值只是首字母大写(如Cuser),则绑定数据时使用Cuser或C-user均可。

    自定义事件 

    子传父应用场景说明参考

    通过自定义事件($emit)可以实现子组件传递数据或事件到父组件中。

    主要流程:

    • 在子组件中,通过 $emit来触发事件。
    • 在父组件中,通过 v-on来监听子组件事件。

    这部分直接看示例代码吧,用白话讲有点绕。  

    1. <div id="app">
    2. <cpn @itemclick="cpnClcik">cpn>
    3. div>
    4. <template id="cpn">
    5. <div>
    6. <button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}button>
    7. div>
    8. template>
    9. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
    10. <script>
    11. // 父传子:props
    12. const cpn = {
    13. template: "#cpn",
    14. data() {
    15. return {
    16. categoties: [{
    17. id: 'aaa',
    18. name: '热门推荐'
    19. },
    20. {
    21. id: 'bbb',
    22. name: '手机数码'
    23. },
    24. {
    25. id: 'ccc',
    26. name: '家用家电'
    27. },
    28. {
    29. id: 'ddd',
    30. name: '电脑办公'
    31. },
    32. ]
    33. }
    34. },
    35. methods: {
    36. btnClick(item) {
    37. this.$emit('itemclick', item)
    38. }
    39. },
    40. };
    41. const app = new Vue({
    42. el: "#app",
    43. data() {
    44. return {
    45. }
    46. },
    47. methods: {
    48. cpnClcik(item) {
    49. console.log('cpnClick'+item.name);
    50. }
    51. },
    52. components: {
    53. cpn
    54. },
    55. })
    56. script>

    参考:

    https://v2.cn.vuejs.org/v2/guide/components-props.html#Prop-%E7%9A%84%E5%A4%A7%E5%B0%8F%E5%86%99-camelCase-vs-kebab-case

  • 相关阅读:
    Arcgis小技巧【14】——拓扑(Topology)的方方面面
    【深度学习】从LeNet-5识别手写数字入门深度学习
    mysql 问题解决 3
    on java8之复用
    【kali-漏洞利用】(3.1)Metasploitable 操作系统:安装,使用
    python常用内置模块
    SQL存储过程详解
    Win11怎么修改关机界面颜色?Win11修改关机界面颜色的方法
    mysql约束之_唯一约束
    el-select两个下拉框实现二级联动
  • 原文地址:https://blog.csdn.net/weixin_45719444/article/details/126265834