vue 的5中组件通信方式

父组件给子组件传值

  • 子组件中通过props接收父组件传递的数据

  • 父组件给子组件通过属性传值

  • props

    • 类型:Array<string> | Object
  • Object的选项配置

    • type
    • defaultany
    • requiredBoolean
    • validatorFunction,自定义验证函数会将该prop的值作为唯一的参数代入
  • 示例:

    • 父组件

      <template>
        <div>
          <child :title="msg" :age="age"></child>
        </div>
      </template>
      
      <script>
      import child from "./Child";
      export default {
        components: {
          child,
        },
        data() {
          return {
            msg: "我是父组件传递的title",
            age: 18,
          };
        },
      };
      </script>
      
  • 子组件

    • props是数组

      <template>
        <div>
          <h2>title:{{ title }}</h2>
          <h2>age:{{ age }}</h2>
        </div>
      </template>
      
      <script>
      export default {
        props: ["title", "age"],
      };
      </script>
      
    • props是对象

      <template>
        <div>
          <h2>title:{{ title }}</h2>
          <h2>age:{{ age }}</h2>
        </div>
      </template>
      
      <script>
      export default {
        props: {
          title: String,
          age: {
            type: Number,
            default: 0,
            required: true,
            validator: function (value) {
              // 父组件传递的age小于0时会抛出警告:
              // Invalid prop: custom validator check failed for prop "age"
              return value >= 0;
            },
          },
        },
      };
      </script>
      

子组件给父组件传值

  • 在子组件中使用$emit发布一个自定义事件
    • $emit参数:
      • eventName:string
      • [...args]
  • 在父组件中使用v-on或者@监听这个自定义事件
    • 父组件在html中可以使用$event获取传递的值
  • 示例
    • 子组件

      <template>
        <div>
          <h3>{{ Ccount }}</h3>
          <button @click="add">count++</button>
        </div>
      </template>
      
      <script>
      export default {
        props: {
          Ccount: Number,
        },
        methods: {
          add() {
            this.$emit("addCount", this.Ccount);
          },
        },
      };
      </script>
      
    • 父组件

      <template>
        <div>
          <h2>{{ count }}</h2>
          <!-- <child :Ccount="count" v-on:addCount="getCount"></child> -->
          <child :Ccount="count" @addCount="getCount"></child>
          <child :Ccount="count" @addCount="count = $event + 1"></child>
        </div>
      </template>
      
      <script>
      import child from "./02-Child";
      export default {
        components: {
          child,
        },
        data() {
          return {
            count: 1,
          };
        },
        methods: {
          getCount(data) {
            this.count = data + 1;
          },
        },
      };
      </script>
      

不相关组件之间传值

  1. 在组件中创建公共vue实例作为事件中心
    • 使用$emit发布
    • 使用$on订阅
    • 示例:
      • 公共vue实例作为事件中心

        import Vue from 'vue'
        export default new Vue()
        
      • 发布组件

        <template>
          <div>
            <h1>Event Bus Sibling01</h1>
            <div class="number" @click="sub">-</div>
            <input type="text" style="width: 30px; text-align: center" :value="value">
            <div class="number" @click="add">+</div>
          </div>
        </template>
        
        <script>
        import bus from './eventbus'
        
        export default {
          props: {
            num: Number
          },
          created () {
            this.value = this.num
          },
          data () {
            return {
              value: -1
            }
          },
          methods: {
            sub () {
              if (this.value > 1) {
                this.value--
                bus.$emit('numchange', this.value)
              }
            },
            add () {
              this.value++
              bus.$emit('numchange', this.value)
            }
          }
        }
        </script>
        
      • 订阅组件

        <template>
          <div>
            <h1>Event Bus Sibling02</h1>
            <div>{{ msg }}</div>
          </div>
        </template>
        
        <script>
        import bus from "./eventbus";
        export default {
          data() {
            return {
              msg: "",
            };
          },
          created() {
            bus.$on("numchange", (value) => {
              this.msg = `您选择了${value}件商品`;
            });
          },
        };
        </script>
        
  2. main.js文件初始化vue实例时设置事件中心
    • main.js文件

      new Vue({
        render: h => h(App),
        data: {
          eventHub: new Vue()  //使用集中事件处理器,在任何组件调用事件发射和事件接收
        }
      }).$mount('#app')
      
    • 发布组件

      <template>
        <div>
          <h1>Event Bus Sibling01</h1>
          <div class="number" @click="sub">-</div>
          <input type="text" style="width: 30px; text-align: center" :value="value" />
          <div class="number" @click="add">+</div>
        </div>
      </template>
      
      <script>
      
      export default {
        props: {
          num: Number,
        },
        created() {
          this.value = this.num;
        },
        data() {
          return {
            value: -1,
          };
        },
        methods: {
          sub() {
            if (this.value > 1) {
              this.value--;
              this.$root["eventHub"].$emit("numchange", this.value);
            }
          },
          add() {
            this.value++;
            this.$root["eventHub"].$emit("numchange", this.value);
          },
        },
      };
      </script>
      
    • 订阅组件

      <template>
        <div>
          <h1>Event Bus Sibling02</h1>
          <div>{{ msg }}</div>
        </div>
      </template>
      
      <script>
      export default {
        data() {
          return {
            msg: "",
          };
        },
        created() {
          this.$root["eventHub"].$on("numchange", (value) => {
            this.msg = `您选择了${value}件商品`;
          });
        },
      };
      </script>
      

父直接访问子组件——不推荐

  • 通过ref获取子组件

  • ref有两个作用:

    • 如果你把它作用到普通HTML标签上,则获取到的是DOM
    • 如果你把它作用到组件标签上,则获取到的是组件实例
  • 代码示例:

    • 父组件:使用this.$refs.c直接访问子组件

      <template>
        <div>
          <h1>ref Parent</h1>
          {{ msg }}
          <child ref="c" @inputChange="getInputChange"></child>
        </div>
      </template>
      
      <script>
      import child from "./04-Child";
      export default {
        components: {
          child,
        },
        data() {
          return {
            msg: "hello input",
          };
        },
        mounted() {
          this.$refs.c.focus();
          this.$refs.c.value = this.msg;
        },
        methods: {
          getInputChange(val) {
            this.msg = val;
          },
        },
      };
      </script>
      
    • 子组件:watch监听input值的变化,使用$emit通知父组件

      <template>
        <div>
          <h1>ref Child</h1>
          <input ref="input" type="text" v-model="value" />
        </div>
      </template>
      
      <script>
      export default {
        data() {
          return {
            value: "",
          };
        },
        watch: {
          value: function(val) {
            this.$emit("inputChange", val);
          },
        },
        methods: {
          focus() {
            this.$refs.input.focus();
          },
        },
      };
      </script>
      

vuex

  1. 什么是Vuex

    • Vuex是专门为Vue.js设计的状态管理库

    • Vuex采用集中式的方式存储需要共享的数据

    • Vuex的作用是进行状态管理,解决复杂组件通信,数据共享

    • Vuex集成了devtools,提供了time-travel时光旅行历史回滚功能

  2. 什么情况下使用Vuex

    • 非必要的情况不要使用Vuex

    • 大型的单页应用程序

      • 多个视图依赖于同一个状态

      • 来自不同视图的行为需要变更同一状态

Vuex的核心概念

vuex的示例代码:

export default new Vuex.Store({
  strict: process.env.NODE_ENV !== 'production',
  state: {
    count: 0,
    msg: 'Hello Vuex'
  },
  getters: {
    reverseMsg (state) {
      return state.msg.split('').reverse().join('')
    }
  },
  mutations: {
    increate (state, payload) {
      state.count += payload
    }
  },
  actions: {
    increateAsync (context, payload) {
      setTimeout(() => {
        context.commit('increate', payload)
      }, 2000)
    }
  },
  modules: {
    products,
    cart
  }
})
  1. state

    • 单一状态树,用一个对象就包含了全部的应用层级状态,也是响应式的

    • 使用mapState简化state在视图中的使用,mapState返回计算属性

    • 获取state的值

      • 使用this.$store.state获取,示例

        mounted() {
            console.log(this.$store.state.count);
        }
        
      • 使用mapState获取state的值,mapState有两种使用的方式

        • 接收数组参数

          // 该方法是 vuex 提供的,所以使用前要先导入 
          import { mapState } from 'vuex'
          computed: {
              // 不使用`modules`
              ...mapState(['count', 'msg'])
              // 使用`modules`
              ...mapState('module的名称',['count', 'msg'])
          },
          
        • 接收对象参数,可以重命名返回的计算属性的名称

          import { mapState } from 'vuex'
          computed: {
              // 不使用`modules`
              ...mapState({ num: 'count', message: 'msg' })
              // 使用`modules`
              ...mapState('module的名称',{ num: 'count', message: 'msg' })
              /*...mapState({ 
                  num: state => state.count, 
                  message: state => state.msg 
              })*/
          },
          
  2. getter

    • getterstore中的计算属性

    • getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算

    • getter接受state作为第一个参数

    • getter也可以接受其他getter作为第二个参数

    • 使用mapGetter简化视图中的使用

      • mapGettermapState的使用类似,可以接受数组参数,也可以接受对象参数

      • mapGetter示例:

        import { mapGetter } from 'vuex'
        computed: { 
            ...mapGetter(['reverseMsg']), 
            // 重命名,在模板中使用 reverse 
            ...mapGetter({ reverse: 'reverseMsg' }) 
        }
        
  3. mutation

    • Vuex中的mutation非常类似于事件:

    • 不要在mutation中执行异步修改

    • 每个mutation都有一个字符串的事件类型(type)和 一个回调函数(handler)

    • 回调函数就是实际进行状态更改的地方

      • 接受state作为第一个参数

      • 载荷(payload)是第二个参数,是用户执行store.commit的时候传入的额外参数

    • 调用mutation

      • 使用commit提交:this.$store.commit('increate',3)

      • 使用mapMutations提交,示例:

        import { mapMutations } from 'vuex' 
        methods: { 
            // 把increate映射成this.$store.commit('increate',3)
            ...mapMutations(['increate']), 
            // 重命名,在模板中使用 increateMut 
            ...mapMutations({ 
                increateMut: 'increate' 
            }) 
        }
        
  4. action

    • action中可以执行异步操作

    • 修改state需要提交mutation

    • 执行action

      • 使用dispatch,例如:this.$store.dispatch('increateAsync', 5)

      • 可以使用mapActions简化action的调用,示例:

        import { mapActions } from 'vuex'
        methods: {
            // 把increateAsync映射成this.$store.dispatch('increateAsync', 5)
            ...mapActions(["increateAsync"]),
             // 重命名,在模板中使用 increateAction 
             ...mapActions({ increateAction: 'increateAsync' })
        },
        
  5. module

    • Vuex允许我们将store分割成模块(module)。每个模块拥有自己的 statemutationactiongetter

    • module示例:

      const moduleA = {
        state: () => ({ ... }),
        mutations: { ... },
        actions: { ... },
        getters: { ... }
      }
      
      const moduleB = {
        state: () => ({ ... }),
        mutations: { ... },
        actions: { ... }
      }
      
      const store = new Vuex.Store({
        modules: {
          a: moduleA,
          b: moduleB
        }
      })
      
      store.state.a // -> moduleA 的状态
      store.state.b // -> moduleB 的状态
      
  6. 插件

    • Vuex的插件是一个函数,接收一个store的参数

    • store.subscribe:订阅每个store中的mutation,接收的回调函数会在每个mutation完成之后调用

    • 示例:

      // 定义插件
      const myPlugin = store => {
          // store.subscribe:订阅每个store中的mutation,接收的回调函数会在每个mutation完成之后调用
          store.subscribe((mutation, state) => {
              // 每次mutation之后调用的操作
              ....
          })
      }
      
      // 使用插件
      export default new Vuex.Store({
          modules: {
              product,
              shoppingCart
          },
          plugins: [myPlugin]
      })
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值