手把手写一个vue3的组件

本文详细介绍了Vue3中组件的创建,包括通用型和业务型组件的区分。通过一个按钮组件的例子展示了如何使用defineProps传递数据,并通过defineEmits注册和抛出事件。此外,还讲解了如何实现v-model的双向绑定,简化了父子组件间的数据传递。最后,提到了插槽的使用,虽然未展开,但强调了其在Vue2和Vue3中的相似性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,组件的分类

我们会把组件分成两个类型,一个是通用型组件,一个是业务型组件。

通用型组件就是各大组件库的组件风格,包括按钮、表单、弹窗等通用功能。业务型组件包含业务的交互逻辑,包括购物车、登录注册等,会和我们不同的业务强绑定。

二,创建一个vue3的组件

🐇defineProps组件间传递数据

以一个按钮组件为例:

//MyButton.vue
<template>
  <div class="button-box">
    <button class="button-content" :style="bgColor">
      {{ buttonName }}
    </button>
  </div>
</template>
<script setup>
import { defineProps, computed } from "vue";
let props = defineProps({
  buttonName: {
    type: String,
    default: "按钮",
    required: true
  },
  bgColorType: {
    type: String,
    default: "white"
  }
});
const bgObj = {
  black: "#00",
  white: "#fff",
  red: "#f5222d",
  orange: "#fa541c",
  yellow: "#fadb14",
  green: "#73d13d",
  blue: "#40a9ff"
};
const bgColor = computed(() => {
  return `background-color:${bgObj[props.bgColorType]};`;
});
</script>
<style>
.button-content {
  border: 1px solid lightskyblue;
}
</style>

使用时:

<template>
  <div class="box"></div>
  <MyButton buttonName="桃花依旧笑春风"></MyButton>
</template>

<script setup>
import MyButton from "../components/MyButton.vue";
</script>

<style></style>

实现的效果:

image-20211124230604051

也就是vue2中的props变成了defineProps来创建。创建后,其内的属性可以直接使用。也可以利用返回的对象.属性值的方式使用。如这里的props.buttonName

🐇组件的事件绑定

在 Vue 中,我们使用 emit 来对外传递事件,这样父元素就可以监听MyButton组件内部的变化。在vue2中使用emit来抛出事件。而在vue3中,我们需要先利用defineEmits先注册要抛出的事件数组,返回一个emit对象。然后利用它来抛出事件。

组件中:

   <button
      class="button-content"
      :style="bgColor"
      @click="buttonClick(buttonName)"
      @mouseover="mouseHover"
    >
      {{ buttonName }}
    </button>
   ....其他代码 
    import { defineProps, defineEmits, computed, ref } from "vue";
    let emits = defineEmits(["buttonClick", "mouseHover"]); // // 注册要抛出的事件数组,返回emits
    function buttonClick(val) {
      //点击触发这个事件,于是调用emit,来抛出事件
      let name = val === "桃花依旧笑春风" ? "人面不知何去处" : "桃花依旧笑春风";
      emits("buttonClick", name);
    }
    function mouseHover() {
      emits("mouseHover");
    }
   ....其他代码 

父组件的使用:

<template>
  <div class="box"></div>
  <MyButton
    :buttonName="buttonContent"
    :bgColorType="bgtype"
    @buttonClick="myButtonClick"
    @mouseHover="myBtnHover"
  ></MyButton>
</template>

<script setup>
import MyButton from "../components/MyButton.vue";
import { ref } from "vue";
let bgtype = ref("white");
let buttonContent = ref("桃花依旧笑春风");
function myButtonClick(val) {
  buttonContent.value = val;
}
function myBtnHover() {
  bgtype.value = "orange";
  setTimeout(() => {
    bgtype.value = "white";
  }, 1000);
}
</script>

<style></style>
🐇组件间的数据传递v-model

前两点,一个是父组件向子组件传值,另一个是子组件给父组件传值。上文中这种要实现的实际上是数据的双向绑定问题,可以使用v-model来简化。

子组件:

 <button
      class="button-content"
      :style="bgColor"
      @click="buttonClick(buttonName)"
      @mouseover="mouseHover"
    >
      {{ buttonName }}
    </button>
    
import { defineProps, defineEmits, computed, ref } from "vue";
let props = defineProps({
  buttonName: {
    type: String,
    default: "按钮"
  },
  bgColorType: {
    type: String,
    default: "white"
  }
});
let emits = defineEmits(["update:buttonName", "mouseHover"]);
function buttonClick(val) {
  let newval = val === "桃花依旧笑春风" ? "人面不知何去处" : "桃花依旧笑春风";
  emits("update:buttonName", newval);//依旧是要用emit抛出,只是用v-model,让父组件少了一步定义函数,然后更新数据罢了。
}

父组件:

<template>
  <div class="box"></div>
  <MyButton
    v-model:buttonName="buttonContent"
    :bgColorType="bgtype"
    @mouseHover="myBtnHover"
  ></MyButton>
</template>

<script setup>
import MyButton from "../components/MyButton.vue";
import { ref } from "vue";
let bgtype = ref("white");
let buttonContent = ref("桃花依旧笑春风");
// function myButtonClick(val) {
//   buttonContent.value = val;
// }//相较而言,只是少了这一步而已
function myBtnHover() {
  bgtype.value = "orange";
  setTimeout(() => {
    bgtype.value = "white";
  }, 1000);
}
</script>

<style></style>

🐇插槽

插槽写法和vue2没啥差别,就不说了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值