680 vue3组件的通信:过props,$emit,非Prop的Attribute

组件的通信


父子组件之间通信的方式


父组件传递给子组件


Props的数组用法


Props的对象用法


细节一:type的类型都可以是哪些呢?


细节二:对象类型的其他写法


细节三:Prop 的大小写命名


非Prop的Attribute


禁用Attribute继承和多根节点


App.vue

<template>
  <div>
    <show-message id="abc" class="why" title="哈哈哈" content="我是哈哈哈哈" message-info=""></show-message>
    <show-message title="呵呵呵" content="我是呵呵呵呵"></show-message>
    <show-message :title="title" :content="content"></show-message>

    <show-message :title="message.title" :content="message.content"></show-message>
    <show-message v-bind="message"></show-message>

    <multi-root-element id="aaaa"></multi-root-element>

    <!-- 补充 -->
    <!-- 写成小驼峰personalInfo 也是可以的 -->
    <!-- <show-message :personalInfo="personalInfo"></show-message> -->
    <!-- <show-message :personal-info="personalInfo"></show-message> -->
  </div>
</template>

<script>
  import ShowMessage from './ShowMessage.vue';
  import MultiRootElement from './MultiRootElement.vue';

  export default {
    components: {
      ShowMessage,
      MultiRootElement
    },
    data() {
      return {
        title: "嘻嘻嘻",
        content: "我是嘻嘻嘻嘻",
        message: {
          title: "嘿嘿嘿",
          content: "我是嘿嘿嘿"
        }
      }
    }
  }

  console.log()
</script>

<style scoped>
</style>

ShowMessage.vue

<template>
  <div>
    <h2 v-bind="$attrs">{{title}}</h2>
    <p>{{content}}</p>
  </div>
</template>

<script>
  export default {
    // props: ['title', 'content']
    inheritAttrs: false,
    props: {
      title: String,
      content: {
        type: String,
        required: true,
        default: "123"
      },
      counter: {
        type: Number
      },
      info: {
        type: Object,
        default() {
          return {name: "why"}
        }
      },
      messageInfo: {
        type: String
      }
    }
  }
</script>

<style scoped>
</style>

MultiRootElement.vue

<template>
  <h2>MultiRootElement</h2>
  <h2>MultiRootElement</h2>
  <!-- 【如果子组件是多个根元素,那么就要明确指定哪个根元素用到了父组件传递的属性。】 -->
  <!-- 【如果子组只有一个根元素,那么根元素会自动接收父组件传递的属性。也可以明确指定根元素的子元素接收,此时根元素和子元素就同时接收了。】 -->
  <h2 :id="$attrs.id">MultiRootElement</h2>
</template>

<script>
  export default {
    
  }
</script>

<style scoped>
</style>

子组件传递给父组件


自定义事件的流程


自定义事件的参数和验证


App.vue

<template>
  <div>
    <h2>当前计数: {{ counter }}</h2>
    <counter-operation @add="addOne" @sub="subOne" @addN="addNNum"></counter-operation>
  </div>
</template>

<script>
import CounterOperation from './CounterOperation.vue';

export default {
  components: {
    CounterOperation
  },
  data() {
    return {
      counter: 0
    }
  },
  methods: {
    addOne() {
      this.counter++
    },
    subOne() {
      this.counter--
    },
    addNNum(num, name, age) {
      console.log(name, age);
      this.counter += num;
    }
  }
}
</script>

<style scoped>
</style>

CounterOperation.vue

<template>
  <div>
    <button @click="increment">+1</button>
    <button @click="decrement">-1</button>
    <hr>
    <input type="text" v-model.number="num">
    <button @click="incrementN">+n</button>
  </div>
</template>

<script>
  export default {
    // 先注册
    emits: ["add", "sub", "addN"],
    // 对象写法的目的是为了进行参数的验证
    // emits: {
    //   add: null, // null表示不需要验证
    //   sub: null,
    //   addN: (num, name, age) => {
    //     console.log(num, name, age);
    //     if (num > 10) {
    //       return true
    //     }
    //     return false;
    //   }
    // },
    data() {
      return {
        num: 0
      }
    },
    methods: {
      increment() {
        console.log("+1");
        this.$emit("add");
      },
      decrement() {
        console.log("-1");
        this.$emit("sub");
      },
      incrementN() {
        this.$emit('addN', this.num, "why", 18);
      }
    }
  }

  new Array()
</script>

<style scoped>
/* CEBE8C  D8BE88  CEBE8E */
</style>

组件间通信案例练习


App.vue

<template>
  <div>
    <tab-control :titles="titles" @titleClick="titleClick"></tab-control>
    <h2>{{contents[currentIndex]}}</h2>
  </div>
</template>

<script>
  import TabControl from './TabControl.vue';

  export default {
    components: {
      TabControl
    },
    data() {
      return {
        titles: ["衣服", "鞋子", "裤子"],
        contents: ["衣服页面", "鞋子页面", "裤子页面"],
        currentIndex: 0
      }
    },
    methods: {
      titleClick(index) {
        this.currentIndex = index;
      }
    }
  }
</script>

<style scoped>
</style>

TabControl.vue

<template>
  <div class="tab-control">
    <div class="tab-control-item" 
         :class="{active: currentIndex === index}"
         v-for="(title, index) in titles" 
         :key="title"
         @click="itemClick(index)">
      <span>{{title}}</span>
    </div>
  </div>
</template>

<script>
const 
  export default {
    emits: ["titleClick"],
    props: {
      titles: {
        type: Array,
        default() {
          return []
        }
      }
    },
    data() {
      return {
        currentIndex: 0
      }
    },
    methods: {
      itemClick(index) {
        this.currentIndex = index;
        this.$emit("titleClick", index);
      }
    }
  }
</script>

<style scoped>
  .tab-control {
    display: flex;
  }

  .tab-control-item {
    flex: 1;
    text-align: center;
  }

  .tab-control-item.active {
    color: red;
  }

  .tab-control-item.active span {
    border-bottom: 3px solid red;
    padding: 5px 10px;
  }
</style>


原文地址:https://www.cnblogs.com/jianjie/p/14855345.html