前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【BlogAdmin升级3】组件通讯与引用

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

作者头像
老张的哲学
发布2024-02-22 15:40:36
1190
发布2024-02-22 15:40:36
举报
文章被收录于专栏:NetCore 从壹开始

父传子

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

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

子传父

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

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

子组件

代码语言:javascript
复制
<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>

父组件

代码语言:javascript
复制
<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编译宏指定哪些属性和方法允许访问

子组件

代码语言:javascript
复制
<script setup>
const count = 999
const sayHi = () => {
    console.log("你好")
}
defineExpose({
    count,
    sayHi
})
</script>
<template>
    <div>
        我是子组件 - {{ 999 }}
    </div>
</template>

父组件

代码语言:javascript
复制
<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

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

底层

代码语言:javascript
复制
<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>

中间

代码语言:javascript
复制
<script setup>
import childBottom from '@/components/child-bottom.vue'
</script>
<template>
    <h2>我是中间组件</h2>
    <childBottom></childBottom>
</template>

顶层

代码语言:javascript
复制
<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来做到)

代码语言:javascript
复制


// <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">

相当于

代码语言:javascript
复制
<Child :modelValue="isVisible" @update:modelValue="isVisible=$event">

我们需要先定义props,

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

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

子组件

代码语言:javascript
复制
<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>

父组件

代码语言:javascript
复制
<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

实现步骤

引入

代码语言:javascript
复制


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')

定义

代码语言:javascript
复制
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'] //定义某个变量持久化
  }
)

使用

代码语言:javascript
复制
<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>
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-02-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 NetCore 从壹开始 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档