likes
comments
collection
share

初识vue-组件及组件传值

作者站长头像
站长
· 阅读数 8

前言

组件是什么? 简单理解,组件就是至现在为止,逻辑的最高复用。 在vue里 每一个以.vue结尾的文件都是一个组件,它可以被多次调用,且每次运行都是独立的。组件内包含了js、css、html。所以当你调用这个组件的时候相当于复用了这个组件内的js逻辑、css样式、html片段。 该如何定义和使用组件呢?

component 组件

定义组件

当我们创建好了一个.vue文件,它就是一个正常的组件了,当然这没有意义,并且没有默认导出的话会有报错的,在组件内写好template和script标签,并在script标签内默认导出就可以

  List.vue

//这里就是一个最简单的list组件
<template>
  <ul>
    <li v-for="item in arr" :key="item">{{ item }}</li>
  </ul>
</template>
<script>
export default {
  data() {
    return {
      arr: [1, 2, 3, 4, 5, 6],
    };
  },
};
</script>

组件定义好了,该如何使用。可以选择其他一个任意一个.vue的组件,然后在组件内引用并定义就可以了,当访问父组件的时候,显示的就是引入组件的内容了

//Home.vue
<template>
 3、//在模板使用组件就是在components内定义的组件名字
 //这里显示的就是List组件内的内容
  <List />
</template>
<script>
1、 //需要在script标签内引入组件
import List from "./List.vue";
export default {
2、//需要在components属性内定义
  components: {
    List,
  },
  data() {
    return {};
  },
};
</script>

以上就是在vue内定义和使用组件基本内容,组件的特点即是低耦合性,高复用性,我们不仅要使用组件写出单独的一个页面,还可以考虑场景对一些重复的内容进行封装,然后进行重复使用,减少代码逻辑和代码量,让代码页面更美观,但上面这种组件大多情况下不能很好的逻辑复用,因为它内部是固定的内容,这时候就引出组件传值

组件传值

组件之间的数据传递有很多,例如: props,emit,v-model,provide,inject,bus(vue2),ref,vuex,pinia

props父传子、emit子传父

vue中最常见的和使用最普遍的就是propsemit 如何使用:

Home.vue
  //父传子  在引入的组件上添加属性 属性可以是动态绑定的
  <List title="标题" :name="new Date().getMonth()>6?'水娃':'火娃'"/>

 
List.vue

<template>
  <button>{{ title }}</button>//这里按钮显示的就是标题
  <div>你是{{ name }}</div>//如果父组件内的条件成立 那么是  你是水娃 否则是  你是火娃
</template>
<script>
export default {
//那么在子组件内使用props接收就可以了
  props: ["title",'name'],
  data() {
    return {
      newName:this.name//props在js里使用需要加上this.xxx 跟访问响应数据一致
    };
  },
};
</script>

 // //有时候想要接收固定类型和有默认值的props参数,这个时候可以将props写成对象形式
 List.vue
 <template>
  <button>{{ title }}</button>//当父组件没有传入title参数时 这里为'题目'
  <div>你是{{ name }}</div>//当父组件没有传入name参数时,这里为'你是[]'
</template>
<script>
export default {
  props: {
    //接收参数的名字
    name: {
      type: Number, //定义接收参数的类型
      default: "题目", //默认值
      required: true, //是否必须传参
    },
    title: {
      type: String | Number | Array, //定义多个类型(vue2)
      default: () => [], //默认值,引用类型需要是工厂函数
    },
  },
};
</script>

注意

要注意的是接收的参数是字符串,避免写成变量,使用props父传子的值为单向数据,在子组件内不可更改父组件传递过来的值,如果想要改变,必须在父组件内更改,或者使用emit

emit子传父

为什么需要子传父? 就上面讲的,当在子组件内想要改变传进来的数据,且又因为父子传参是单向数据流,必须要改变父组件里的数据,才能达到组件修改数据的需求

Home.vue
//子传父 在父组件内引入的组件上写上v-on:emit传出来的事件名 
//当子组件调用了emit 直接会触发父组件内部的方法,切记在父组件内调用的方法名上不要加()
//否则接收不到子组件内传出来的值
<template>
  <List :title="title" @setTitle="changeTitle" />
</template>
<script>
import List from "./List.vue";
export default {
  components: {
    List,
  },
  data() {
    return {
      title: "标题",
    };
  },
  methods: {
    changeTitle(value) {
      this.title = value;
    },
  },
};

List.vue
//子组件内 ,当点击了这个按钮 会触发setTitle事件 调用emit 触发父组件内的方法 更改传递进来的props
//更新title
<template>
//没点击按钮之前是标题  点击之后 按钮名为'我真的不懂vue'
  <button @click="setTitle">{{ title }}</button>
</template>
<script>
export default {
  props: {
    title: {
      type: String,
      default: "",
    },
  },
  data() {
    return {};
  },
  methods: {
    setTitle() {
    //此事件触发,调用emit,第一个是方法名,第二个是传递的参数
      this.$emit("setTitle", "我真的不懂vue");
    },
  },
};
</script>
</script>


bus 中央事件总线(vue2)

父传子,子传父都会了,但是会有情况是兄弟组件之间传递参数,只使用props和emit会有些许麻烦,所以在vue2中有个bus中央事件总线的方法,顾名思义 就是可以有个组件作为中间件,利用发布订阅者模式,来提供兄弟组件之间的数据传递

main.js
//main文件中定义中央事件总线并挂载到vue原型上
import Vue from 'vue'
const bus=new Vue()
Vue.prototype.bus=bus  //此时就可以在vue想用的任意位置使用了

List.vue
//使用emit发布事件
this.bus.$emit('fn','携带的参数')

List1.vue
//使用on订阅事件
this.bus.$on('fn',v=>console.log(v))//这里就是'携带的参数'

//使用off移除事件 
//当事件获得参数使用完之后 如果后续不再使用 可以使用off移除事件
this.bus.$off('fn') 

注意

在使用完bus之后,建议立马移除事件,如果大量的bus事件使用后没有移除,会造成内存泄漏

provide、inject 依赖注入

当组件内部传入的数据比较深可以使用数据注入来达到深层次的组件传值,使用比较简单

Home.vue
//在祖组件内可以直接给provide属性赋值一个对象,对象内的属性及属性值就可以被inject接收到了
export default {
  provide: {
    context:this.title
    //(context:this.newTitle)//如果想要注入响应式参数 可以利用计算属性的特性来实现
  },
  data() {
    return {
      title: "标题",
    };
  },
   computed: {
    newTitle: () => this.title,//当title变更时,计算属性会自动收集依赖,并改变当前数据
  },
};


List.vue
//此时模板中按钮的文字为 标题
<template>
  <button >{{ context }}</button>
</template>

//在孙子组件内接收注入的值,数组内的参数为祖辈组件传进来的属性值
export default {
   inject: ['context'],
};

注意

当封装复用组件时,不建议使用依赖注入,因为组件的复用性、低耦合性,如果在复用组件内使用依赖注入,会出现一些特定的问题,也不利于组件的复用

v-model双向绑定

v-model指令之前写过,是绑定表单的一个语法糖,但是在组件这里依旧适用 当子组件内需要props接收一个参数并且还需要根据这个参数来emit一个方法,这个时候就可以使用v-model指令了

(以下是vue2中的v-model双向绑定的写法,vue3的我还能再水一章§(* ̄▽ ̄*)§)
Home.vue
//在父组件内,给子组件上添加v-model绑定值
<template>
  <button @click="title = '题目'">题目</button>
  <List v-model="title" />
</template>
<script>
import List from "./List.vue";
export default {
  components: {
    List,
  },
  data() {
    return {
      title: "标题",
    };
  },
};
</script>

List.vue
//当不点击任何按钮时,子组件的button为标题 
//当点击了子组件的按钮时 子组件的按钮为'子组件' 会立即触发emit并映射到父组件的title上
//然后props接受到的参数就为父组件的title
//当点击了父组件的按钮  子组件的按钮为'题目'
<template>
  <button @click="$emit('change', '子组件')">{{ title }}</button>
</template>
<script>
export default {
  props: {
    title: {
      type: String,
      default: "",
    },
  },
  //这里是v-mode双向绑定组件关键
  model: {
    prop: "title",//传进来某个的props
    event: "change",//v-mode要触发的事件名
  },
};
</script>

vuex和pinia 公共状态

--vuex和pinia的东西比较多,这次就先说一下概念,使用以后再写

Vuex和Pinia都是Vue状态管理库,用于在Vue应用中进行全局状态管理。它们有一些共同点,但也有一些区别。

相同点:

  1. 都提供了一种集中式的状态管理解决方案,可以在应用的各个组件中共享和修改状态。
  2. 都基于Vue的响应式系统,当状态发生变化时,相关的组件会自动更新。

区别:

  1. API设计:Vuex使用了一种基于mutations和actions的方式来管理和修改状态,而Pinia则更倾向于使用类似于Composition API的方式来组织和处理状态。
  2. 安装方式:Vuex是一个Vue的官方插件,可以通过Vue.use()方法进行安装,而Pinia是一个独立的库,需要在Vue应用中单独引入和实例化。
  3. 性能优化:Pinia通过使用Proxy代理对象来实现状态的响应式,相较于Vuex的Vue.set()方法,Pinia在性能上有一些优势。
  4. TypeScript支持:Pinia天生支持TypeScript,提供了更好的类型推断和类型检查,而Vuex对TypeScript的支持相对较弱。

选择使用Vuex还是Pinia取决于个人偏好和项目需求。如果你已经熟悉Vuex并且项目中已经使用了Vuex,那么可以继续使用它。如果你喜欢使用Composition API或者需要更好的TypeScript支持,那么可以考虑尝试Pinia。

结尾

基本组件以及组件通讯差不多就这些,vue2和vue3有些许不同,以上均为vue2中的写法,vue3我还得水文章呢~( ̄▽ ̄)~*

预告:后面更新可能会是插槽内容···