【BlogAdmin升级3】组件通讯与引用

科技   2024-02-03 20:03   北京  

父传子

1.父组件中给子组件绑定属性

2.子组件内部通过props选项接收

子传父

1.父组件中给子组件标签通过@绑定事件

2.子组件内部通过emit方法触发事件


子组件

<script setup>// 由于写setup,所以无法直接配置props选项// 所以需要借助"编译器宏"函数接收父组件传递的数据const props = defineProps({    car: String,    money: Number,    addMoney: Function})console.log(props.car)



//子传父const emit = defineEmits(['change-Money'])const buy = () => { emit('change-Money', 5)}</script><template> <div class="son"> <!-- 子组件可以直接使用传递过来的数据 --> 我是子组件 - {{ car }} - {{ money }} - <button @click="addMoney">+1</button> <div> <button @click="buy">-Money</button></div> </div> </template><style>.son { border: 1px solid #000; padding: 30px;}</style>


父组件

<script setup>//父传子// 1.给子组件,添加属性方式传值// 2.子子组件,通过props接收import mychild from '@/components/mychild.vue'

// 传递动态值import { ref } from 'vue';const money = ref(100)

const addMoney = () => { money.value++}



//子传父// 1.在子组件内部,emit触发事件// 2.在父组件通过@监听const changeFn = (m) => { money.value -= m}</script>

<template> <div> 父组件 - {{ money }} - <button @click="addMoney">+1</button> <mychild car="我是父组件传过来的参数" :money="money" :addMoney="addMoney" @change-Money="changeFn"></mychild> </div></template>

defineProps原理: 就是编译阶段的一个标识,实际编译器解析时,遇到后就会进行编译转换

模板引用

通过ref标识获取真实的dom对象或者组件实例对象

1.调用ref函数生成一个ref对象

2.通过ref表示绑定ref对象到标签

defineExpose()

默认情况下<script setup>语法糖下组件的属性和方法是不开放给父组件的

可以用过defineExpose编译宏指定哪些属性和方法允许访问


子组件

<script setup>const count = 999const sayHi = () => {    console.log("你好")}defineExpose({    count,    sayHi})</script><template>    <div>        我是子组件 - {{ 999 }}    </div></template>


父组件

<script setup>import myRefChild from '@/components/my-ref-child.vue'import { ref, onMounted } from 'vue';// 模板引用,可以获取dom,也可以获取组件// 1.调用ref函数,生成一个ref对象// 2.通过ref标识进行标定// 3.通过ref对象.value即可访问到绑定的元素(必须渲染后才能拿到)const myInput = ref(null)

onMounted(() => { console.log("myInput") // myInput.value.focus()})

const clickFn = () => { myInput.value.focus()}



const myChild = ref(null)

const getMyDom = () => { console.log(myChild.value) myChild.value.sayHi()}onMounted(() => { console.log(myChild.value)

})</script>

<template> <div> <input ref="myInput" type="text" /> <button @click="clickFn">点击输入聚焦</button>

<div> <myRefChild ref="myChild"></myRefChild> <button @click="getMyDom">获取组件信息</button> </div> </div></template>


provide和inject

顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信

底层

<script setup>

import { inject } from 'vue';

const themeColor = inject('theme-color')

const count = inject('count')const changeCount = inject('changeCount')const changeFn = () => { changeCount(1000)}</script><template> <h3>我是底层组件 - {{ themeColor }} - {{ count }}</h3> <button @click="changeFn">更新count</button></template>

中间

<script setup>import childBottom from '@/components/child-bottom.vue'</script><template>    <h2>我是中间组件</h2>    <childBottom></childBottom></template>

顶层

<script setup>import childCenter from '@/components/child-center.vue'

import { provide, ref } from 'vue';

// 跨层传递普通数据provide('theme-color', 'pink')

// 跨层传递响应式数据const count = ref(100)provide('count', count)

setTimeout(() => { count.value = 200}, 2000);

//跨层级传递函数,方便子组件修改父组件的数据,提供方法进行修改provide('changeCount', (newCount) => { count.value = newCount})</script><template> <h1>我是顶层组件 - {{ count }}</h1> <childCenter></childCenter></template>

defineOptions(vue 3.3)

有<script setup>之前,如果要定义 props,emits 可以轻而易举地添加一个与 setup 平级的属性

但是用了<script setup> 后,就没法这么干了 setup 属性已经没有了,自然无法添加与其平级的属性

为了解决这一问题,引入了 defineProps 与 defineEmits 这两个宏。

但这只解决了 props 与emits 这两个属性如果我们要定义组件的 name 或其他自定义的属性,

还是得回到最原始的用法一再添加一个普通的<script>标签这样就会存在两个<script> 标签。

让人无法接受


所以在 Vue 3.3 中新引入了 defineOptions 宏。

顾名思义,主要是用来定义 Options API 的选项。可以用define0ptions定义任意的选项,props,emits,expose, slots 除外(因为这些可以使用 defineXXX来做到)



// <script>// export default {// name: "test"// }// </script>

<script setup>defineOptions({ name: 'test'})</script><template> <div>Hello</div></template>


defineModel

在Vue3中,自定义组件上使用v-model,相当于传递一个modelValue属性,同时触发 update:modelvalue 事件<Child v-model="isVisible">

相当于

<Child :modelValue="isVisible" @update:modelValue="isVisible=$event">

我们需要先定义props,

再定义emits。其中有许多重复的代码。

如果需要修改此值,还需要手动调用 emit 函数


子组件

<script setup>import { defineModel } from 'vue';const modelValue = defineModel()const changeFn = () => {    modelValue.value += 1}</script><template>    <div>        <input type="text" :value="modelValue" @input="e => modelValue = e.target.value" />        {{ modelValue }}        <button @click="changeFn">子组件更新</button>    </div></template>


父组件

<script setup>import { ref } from 'vue';import myInput from '@/components/my-input.vue'

const count = ref(100)

const changeFn = () => { count.value += 1}</script><template> <div> <myInput v-model="count"></myInput> <div>{{ count }} - <button @click="changeFn">父组件更新</button></div> </div></template>

Pinia

Pinia是Vue 的最新状态管理工具,是Vuex的替代品


特点

1.提供更加简单的API (去掉了 mutation )

2.提供符合,组合式风格的API (和Vue3 新语法统一)

3.去掉了 modules 的概念,每一个 store 都是一个独立的模块

4.配合TypeScript 更加友好,提供可靠的类型推断


配置

手动添加Pinia到Vue项目

在实际开发项目的时候,关于pinia的配置,可以在项目创建时自动添加现在我们初次学习,从零开始:

1使用 Vite 创建一个空的 Vue3 项目

npm create vue@latest

2按照官方文档安装 pinia 到项目中

Pinia基础使用 - 计数器案例

1.定义store

2.组件使用store


实现步骤

引入



import { createApp } from 'vue'import persist from 'pinia-plugin-persistedstate'import { createPinia } from 'pinia'const pinia = createPinia(); //创建pinia实例//导入pinia持久化插件pinia.use(persist)

import App from './App.vue'

createApp(App).use(pinia).mount('#app')


定义

import { defineStore } from "pinia";import { ref } from "vue";import { computed } from 'vue';//定义store// defineStore(仓库唯一标识,()=>{...})

export const useCounterStore = defineStore("counter", () => { //声明数据 state - count const count = ref(100) //声明操作数据的方法 action(普通函数) const addCount = () => { count.value++ } const subCount = () => { count.value-- } //声明基于数据派生的计算属性 getters(计算属性computed) const double = computed(() => count.value * 2) //声明数据 state - msg const msg = ref("hello pinia")

return { count, msg, addCount, subCount, double }}, { //persist: true //开启持久化 persist:{ key:'自定义持久化key', paths:['count'] //定义某个变量持久化 })


使用 

<script setup>

import Son1 from './components/Son1.vue';import Son2 from './components/Son2.vue';

import { useCounterStore } from '@/store/counter.js'const counterStore = useCounterStore();





console.log(counterStore)</script>

<template> <h1>{{ counterStore.count }}</h1> <h1>{{ counterStore.msg }}</h1> <son-1></son-1> <son-2></son-2></template>

<style scoped></style>


BCVP代码创新社
专注于 NetCore 相关技术栈的推广,致力于前后端之间的完全分离,从壹开始,让每一个程序员都能从这里学有所成。
 最新文章