第六章 vue组件通信

父传子

单向数据流

单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。(子组件不能修改prop)

  • 对象和数组是通过引用传入的,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。

vue2语法

基本用法

传递静态或动态 Prop

<!-- 传入静态值 -->
<blog-post title="hai hai hai"></blog-post>

<!-- 传入变量值 -->
<blog-post :title="info.title"></blog-post>

传入一个对象的所有 property

post: {
  id: 1,
  title: 'My Journey with Vue'
}
<blog-post v-bind="post"></blog-post>

<!-- 等价于 -->
<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

props接收

  1. 数组形式
props: ['propA', 'propB']
  1. 对象形式
Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
      //箭头函数语法,括号()内为js表达式,即return返回的值
      //default: ()=>({message: 'hello'})
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].includes(value)
      }
    }
  }
})
  • Object,Array,Function等引用类型的默认值为函数形式(防止污染)

非 Prop 的 Attribute

父组件传递的属性,子组件并没有相应prop去接收
默认这些 attribute 会被添加到这个子组件的根元素上
例如:id、class、style等属性,子组件没有显示的用props接收

父组件传递数据:

<HelloWorld :name="name" :age="age" :test="123"></HelloWorld>

子组件接收数据:
没有props接收test,故test为非Prop的Attribute,默认test添加到子组件的根元素上

<template>
  <div class="outer">
    <div class="box">
      <div>
        <h1>{{ name }}</h1>
        <h1>{{ age }}</h1>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    name: {
      type: String,
      default: 'none'
    },
    age: {
      type: Number,
      default: 0
    },
  }
}
</script>

在这里插入图片描述

指定Attribute绑定的元素

<template>
  <div class="outer">
    <div class="box">
      <div>
      	<!-- 指定Attribute绑定的元素 -->
        <h1 :test="$attrs.test">{{ name }}</h1>
        <h1>{{ age }}</h1>
      </div>
    </div>
  </div>
</template>

<script>
export default {
 //禁用 Attribute继承
  inheritAttrs:false,
  props: {
    name: {
      type: String,
      default: 'none'
    },
    age: {
      type: Number,
      default: 0
    },
  }
}
</script>

在这里插入图片描述

Vue3语法

基本用法

父组件App.vue

<template>
  <div class="App">
    <TestA :title="title" :arr="arr" :obj="obj"></TestA>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'
import TestA from './components/TestA.vue';

const title = ref('ccc')
const arr = ref([1,2,3])
const obj = ref({
  id: 1,
  gender: 'female'
})

</script>

子组件TestA.vue

  1. ts语法
<template>
  <div class="TestA">
    <h1>{{ title }}</h1>
    <h1>{{ arr }}</h1>
    <h1>{{ obj }}</h1>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'

// ts语法
const props = withDefaults(defineProps<{
  title: string,
  arr: number[],
  obj: {id:number,gender:string}
}
>(),{
  title: 'defaultTitle',
  arr: ()=>[0],
  obj: ()=>({id:0,gender:'male'})
})
console.log(props.title);
console.log(props.arr);
console.log(props.obj);

</script>
  1. js语法
<template>
  <div class="TestA">
    <h1>{{ title }}</h1>
    <h1>{{ arr }}</h1>
    <h1>{{ obj }}</h1>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'

// js语法
const props = defineProps({
  title:{
    type:String,
    default: 'defaultTitle'
  },
  arr: {
    type: Array,
    default: ()=>[0]
  },
  obj: {
    type: Object,
    default: ()=>({})
  }
})
console.log(props.title);
console.log(props.arr);
console.log(props.obj);

</script>

子传父

Vue2语法

子组件HelloWorld.vue

<template>
  <div>
    <button @click="handleClick(1)">+1</button>
    <button @click="handleClick(2)">+2</button>
    <button @click="handleClick(3)">+3</button>
  </div>
</template>

<script>
export default {
  // 1.自定义事件的声明
  // 方式1 数组
  // emits: ['add'],
  // 方式2 对象(参数验证)
  emits: {
    add: function (payload) {
      // add的值<=1时,抛出事件add
      return payload <= 1 ? true : false
    },
  },
  methods: {
    handleClick(num) {
      // 2.抛出自定义事件add
      this.$emit('add', num)
    },
  },
}
</script>

父组件App.vue

<template>
  <div>
    <h1>{{ count }}</h1>
    <!-- 1.监听自定义事件add -->
    <hello-world @add="handleAdd"></hello-world>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue';

export default {
  components: { HelloWorld },
  data() {
    return {
      count: 0
    }
  },
  methods: {
   // 2.实现自定义事件add的回调函数
    handleAdd(num) {
      this.count += num
    },
  },
}
</script>

在这里插入图片描述

Vue3语法

子组件A.vue

  1. js语法
<template>
  <div>
    <button @click="handleClick(1)">+1</button>
    <button @click="handleClick(2)">+2</button>
    <button @click="handleClick(3)">+3</button>

  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

// 1.js语法
const emits = defineEmits(['addNum'])
function handleClick(num) {
  // 抛出自定义事件
  emits('addNum', num)
}
</script>
  1. ts语法
<template>
  <div>
    <button @click="handleClick('addNum',1)">+1</button>
    <button @click="handleClick('addNum',2)">+2</button>
    <button @click="handleClick('addNum',3)">+3</button>

  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'

// 2.ts语法
const handleClick = defineEmits<{
  (e:"addNum", num:number):void
}>()

</script>

父组件App.vue

<template>
  <div>
    <h1>{{ count }}</h1>
    <A @addNum="addNum"></A>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import A from '@/components/A.vue'

const count = ref(100)

function addNum(payload) {
  count.value += payload
}
</script>

插槽

Vue插槽

provide与inject

Vue2中使用

在这里插入图片描述
在这里插入图片描述
变为响应式数据:computed函数
在这里插入图片描述

Vue3中使用

App.vue

<template>
  <div>
    <A></A>
    <button @click="handleClick">+1</button>
  </div>
</template>

<script setup>
import { provide, ref, reactive } from 'vue'
import A from '@/components/A.vue'

// provide的数据默认是非响应式的
// ref或reactive变为响应式
const name = ref("cjc")
const age = ref(0)
provide("name",name)
provide("age", age)

function handleClick() {
  age.value++
}
</script>

A.vue

<template>
  <div>
    <h1>{{ name }}</h1>
    <h1>{{ age }}</h1>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, inject } from 'vue'

const name = inject("name", '默认值')
const age = inject("age")

</script>

全局事件总线

使用第三方库mitt,tiny-emitter
mitt

ref 获取DOM或组件实例

vue2

获取具有ref属性的所有DOM元素和组件实例
App.vue

<template>
  <div>
    <h1 ref="h1Ref">{{ msg }}</h1>
    <A ref="ARef"></A>
  </div>
</template>

<script>
import A from '@/components/A.vue'
export default {
  data() {
    return {
      msg: 'hi'
    }
  },
  components: { A },
  mounted() {

    // 获取DOM元素
    console.log(this.$refs.h1Ref);

    // 获取组件
    console.log(this.$refs.ARef);

    // 获取组件的根元素 this.$refs.ARef.$el
    // 多个根元素时,可以通过DOM方法获取到指定根元素
    console.log(this.$refs.ARef.$el.nextSibling);
  },
}
</script>

<style scoped></style>

A.vue

<template>
  <div>
    <h1>{{ msg }}</h1>
  </div>

  <div>123</div>
</template>

<script>
export default {
  data() {
    return {
      msg: 'A'
    }
  }
}
</script>

Vue3

App.vue

<template>
  <div>
    <h1 ref="h1Ref">App</h1>
    <TestA ref="TestARef"></TestA>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import TestA from './components/TestA.vue';

let h1Ref = ref<HTMLHeadingElement>()
let TestARef = ref<InstanceType<typeof TestA>>()

onMounted(() => {
  // 1. 获取DOM元素
  console.log('1:', h1Ref.value);

  // 2. 获取组件实例,使用组件中defineExpose暴露出来的数据
  console.log('2:', TestARef.value?.foo());
  console.log('3:', TestARef.value?.msg);
})

</script>

A.vue

<template>
  <div>
    <h1>{{ msg }}</h1>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'

const msg = ref('A')
function foo(){
  return 'A.vue foo'
}

defineExpose({
  msg,
  foo
})
</script>

<style scoped></style>

vuex、pinia

vuex知识点
pinia知识点

路由传值

vue-router4知识点

本地存储

本地存储

总结

  1. 父传子,父组件传递属性(静态或动态(v-bind绑定)),子组件通过props接收
  2. 子传父,子组件使用$emit抛出自定义事件,父组件v-on监听自定义事件并实现回调函数
  3. 插槽
  4. 父组件provide提供数据,子孙组件inject注入数据
  5. 通过全局事件总线eventBus进行跨组件值传递
  6. 通过$ref $parent$chidren获取实例进而通信
  7. 通过vuex、pinia进行状态管理
  8. 路由传值
  9. localStorage、sessionStorage
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值