• [vue]数据来源


    1.组件data函数return的数据

    • 作用域是组件本身

    • 可以在模板template及计算属性computed和方法methods中使用

    2.父传子,props数据

    • 来自父级;可以是写死的,或者是来自父级的动态数据,这时可以使用v-bind来绑定props的值

    • 可以在模板template及计算属性computed和方法methods中使用

    • 如果要直接从父组件向子组件传递数字、布尔值、数组、对象,而且不使用v-bind,传递的仅仅是字符串

    • 单向数据流

      • Vue 2.x 通过props传递数据是单向的, 意味着父组件数据变化时才会传递给子组件, 但是反过来不行(Vue1.x 提供了.sync修饰符来支持双向绑定)

      • 之所以这样设计, 目的是尽可能将父子组件解耦,避免子组件无意中修改了父组件的状态

    • 业务中经常会遇到两种需要改变prop的情况

      • 1.父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域下可以随意使用和修改

        • 组件中声明了数据count,它在组件初始化时会获取来自父组件的initCount,之后就与之无关了,只用维护count,这样就可以避免直接操作initCount

      • 2.prop作为需要被转变的原始值传入

        • 通过用计算属性来达到目的

        • S传递宽度要带单位(px),但是每次都写太麻烦,而且数值计算一般是不带单位的,所以统一在组件内使用计算属性就可以了

    • 注意,在JavaScript中对象和数组是引用类型,指向同一个内存空间,所以props是对象和数组时,在子组件内改变时会影响父组件的

    • 数据深拷贝可以解决引用类型父子相互影响的问题

      • 深拷贝就是完完整整的将一个对象从内存中拷贝一份出来。所以无论用什么办法,必然绕不开开辟一块新的内存空间。

    • 数据验证

      • props选项可以是一个数组,但是当需要对prop进行验证时,就需要对象写法

      • 当你的组件需要提供给别人使用时,推荐都进行数据验证

    3.子传父,子组件用$emit触发事件,父组件用$on来监听该事件

    • 原理 dispatchEvent 与 addEventListener;观察者模式常用到的方法

    • 用事件抛出一个特定的值: $emit的第二个参数,父组件监听这个事件时,我们可以通过$event访问到被抛出的这个值(或者这个值将会作为事件处理函数的第一个参数传入)

    • 使用v-model可以用来创建自定义的表单输入组件

    4.Vue.js 1.x 版本 $dispatch(),向上级派发事件;父级(一级或多级)都可以在Vue实例的events选项内接收

     var myComChild = {
            template: '<div><button @click="clickHandler">click</button></div>',
            data () {
                return {
                }
            },
            methods: {
                clickHandler () {
                    this.$dispatch('d-event', 'hello');
                }
            }
        };
        var myCom = {
            template: '<div><my-com-child></my-com-child></div>',
            data () {
                return {
                }
            },
            created () {
                this.$on('d-event', (data) => {
                    // do something
                    console.log('1' + data); // 第一次接收到后停止冒泡
                    return true; // 返回true可以继续冒泡, 使得更高一级的父组件也能接收到该事件
                });
            },
            components: {
                myComChild,
            }
        };
        var vm = new Vue({
            el: '#app',
            data () {
                return {
                }
            },
            created () {
                this.$on('d-event', (data) => {
                    // do something
                    console.log('2' + data);
                });
            },
            components: {
                myCom,
            },
            methods: {
            },
            // events: {
            //  'd-event': function(msg) {
            //      console.log(msg);
            //  }
            // }
        });

    5.Vue.js 1.x版本$broadcast(),由上级向下级广播事件;用法与$dispatch()一致,只是方向相反

    6.使用一个空的Vue实例作为中央事件总线(bus) - 中介者模式

    • 由于Vue.js 1.x版本中的$dispatch() 与 $broadcast() ,基于组件树结构的事件流方式,让人难以理解,并且在组件结构扩展的过程中会变得越来越脆弱,并且不能解决兄弟组件通信的问题

    • 通过bus把组件的事件发布出去, 同时其他组件会接收到来自bus的事件,进而在相应的事件回调中完成自己的业务逻辑

    • 这种方法巧妙而轻量地实现了任何组件间的通信, 包括父子、兄弟、跨级,而且Vue 1.x 和 Vue 2.x都适用

    • 如果深入适用,可以扩展bus实例,给它添加data、method、computed等选项,这些都是可以公用的

      • 在业务中,尤其是协同开发时非常有用,因为经常需要共享一些通用的信息,比如用户登录的昵称、性别、邮箱等,还有用户的授权token等

      • 只需在初始化时让bus获取一次,任何时间、任何组件就可以从中直接使用了,在单页面富应用(SPA)中会很实用

      // eventHub, 注册在组件树的根 Vue 实例中, 通过 this.$root.eventHub.$emit 与 this.$root.eventHub.$on来使用
      // 非组件中的事件总线bus使用方式
      var bus = new Vue();
      var comA = {
          template: '<button @click="clickHandler">传递事件到中央事件总线</button>',
          methods: {
              clickHandler () {
                  bus.$emit('bus-event', '来自组件comA');
              }
          }
      };
      new Vue({
          el: '#app',
          data () {
              return {
                  message: ''
              }
          },
          components: {
              comA,
          },
          mounted () {
              var _this = this;
              bus.$on('bus-event', function (msg) {
                  console.log(msg);
                  _this.message = msg;
              })
          }
      });

    7.父链 this.$parent

    • 在子组件中,使用this.$parent可以直接访问该组件的父实例或组件, 父组件也可以通过this.$children访问它所有的子组件,而且可以递归向上或向下无限访问,直到根实例或最内层的组件

    • 尽管Vue允许这样的操作, 但在业务中,子组件应该尽可能地避免依赖父组件的数据(自己复制一个),更不应该去主动修改它的数据,因为这样使得父子组件紧耦合,只看父组件很难理解父组件的状态,因为它可能被任意组件修改,

    • 理想情况下,只有组件自己能修改它的状态

    • 父子组件最好还是通过props和$emit来通信

      var comA = {
                  template: '<div><button @click="clickHandler">点击修改父元素数据</button></div>',
                  methods: {
                      clickHandler () {
                          // do something
                          // 访问到父链后, 可以做任何操作, 比如直接修改父组件数据
                          this.$parent.message = '来自组件com-a的内容';
                      },
                  }
              };
              new Vue({
                  el: '#app',
                  data () {
                      return {
                          message: ''
                      }
                  },
                  components: {
                      comA,
                  }
              });

    8.子组件索引

    • $ref只在组件渲染完成后才填充,并且它是非响应式的,它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用$refs(非响应式的)

      <div id="app">
              <button @click="clickHandler">通过ref获取子组件实例</button>
              <p ref="p">hello</p>
              <com-a ref="comA"></com-a>
          </div>
          <script src="vue-dev.js"></script>
          <script>
              // 子组件索引
              // 当子组件较多时, 通过this.$children来一一遍历出我们需要的一个组件实例是件困难的事
              // 尤其是组件动态渲染时, 它们的序列是不固定的
              // Vue提供了子组件索引的方法, 用特殊的属性ref来为子组件指定一个索引名称
              var comA = {
                  data () {
                      return {
                          message: '子组件的数据'
                      }
                  },
                  template: '<div><span>this is child component</span></div>',
              };
              new Vue({
                  el: '#app',
                  data () {
                      return {
                      }
                  },
                  components: {
                      comA,
                  },
                  methods: {
                      clickHandler () {
                          // 通过$refs来访问指定的实例
                          var msg = this.$refs.comA.message;
                          console.log(msg);
                          
                          // 与Vue 1.x不同的是, Vue 2.x 将v-el和v-ref合并为了 ref,Vue会去自动判断是普通标签还是组件
                          console.log(this.$refs.comA); // VueComponent 对象
                          console.log(this.$refs.p); // dom 元素 p元素
                      }
                  }
              })
          </script>

    9.slot

    • 在子组件内使用特殊的<slot>元素就可以为这个子组件开启一个slot(插槽),在父组件模板里,插入在子组件标签内的所有内容将替代子组件的<slot>标签及它的内容(如果父组件没有插入内容,子组件<slot>标签里的内容将作为默认出现

    • 单个slot

    • 具名slot;父组件中使用slot特性,匹配子组件中使用了name特性的<slot>;父组件中没有使用slot特性的元素与内容将出现在子组件中没有使用name特性的默认slot中

      <div id="app">
          <my-com>
              <h2 slot="header">标题</h2>
              <p>正文内容</p>
              <div slot="footer">底部信息</div>
          </my-com>
      </div>
      <!-- <script src="libs/vue-v1.0.28/vue.js"></script> -->
      <script src="libs/vue-dev.js"></script>
      <script>
          var myCom = {
              template: '
              <div>
                  <slot name="header"></slot>
                  <slot></slot>
                  <slot name="footer"></slot>
              </div>',
          };
          new Vue({
              el: '#app',
              data () {
                  return {
                  }
              },
              components: {
                  myCom,
              },
          });
      </script>

    10.作用域插槽

    • 作用域插槽是一种特殊的slot,使用一个可以复用的模板替换已渲染的元素

    • 父组件使用了<template>元素,而且拥有一个scope="props"的特性,这里的props只是一个临时变量,就像v-for="item in items"里面的item一样。template可以通过临时变量props来访问来自子组件插槽的数据

    • 作用域插槽的使用场景就是既可以复用子组件的slot,又可以使slot内容不一致

      <div id="app">
          <my-com>
              <template scope="props">
                  <p>来自父组件的内容</p>
                  <p>{{ props.msg }}</p>
              </template>
          </my-com>
      </div>
      <script src="libs/vue-dev.js"></script>
      <script>
          var myCom = {
              template: '<div class="container">
                  <slot msg="来自子组件的内容"></slot>
                  </div>'
          };
          new Vue({
              el: '#app',
              data () {
                  return {
                  }
              },
              components: {
                  myCom,
              }
          })
      </script>
  • 相关阅读:
    [转]Navicat Premium 12试用期的破解方法
    Redis禁用持久化功能的设置
    阿里云ECS安装的redis服务器,用java代码去连接报错。
    关于Jedis连接Linux上的redis出现 DENIED Redis is running in protected mode问题的解决方案
    修改了jdk在环境变量中的路径怎么cmd中的jdk版本没有变
    阿里云上部署tomcat启动后,通过http不能访问
    【终结篇】不要再问我程序员该如何提高了……
    我是怎么把一个项目带崩的
    eterm和easyfare的官网地址
    java UTC时间和local时间相互转换
  • 原文地址:https://www.cnblogs.com/rencoo/p/11741561.html
Copyright © 2020-2023  润新知