美文网首页react & vue & angular
Vite+vue3+Ts+pinia开发(三:父子通讯、兄弟通讯

Vite+vue3+Ts+pinia开发(三:父子通讯、兄弟通讯

作者: 邪七 | 来源:发表于2022-09-21 16:58 被阅读0次

首先你完成了如下:
Vite+vue3+Ts+pinia实战(一:初始、基础安装、踩坑)
Vite+vue3+Ts+pinia开发(二:路由、pinia、UI库安装)

今天就讲讲父子通讯、兄弟通讯,以及ref、reactive的简单使用吧。
父传子Ref基础的HelloWorle.vue就有就不多说了。

初始目录:

image.png

一、在components下建一个组件,我这里叫header吧

// components/Header/index.vue
<template>
    <div class="header">
        <div class="tabs-list">
            <div
                class="tab-item"
                v-for="(item,inx) of tabs"
                :key="inx"
                :class="{'active':cutTab == item.code}"
                @click="tabChange(item)"
            >{{ item.label }}</div>
        </div>
    </div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';

const tabs = reactive([{
    label: "物品查询",
    code: "item"
},
{
    label: "怪物查询",
    code: "mon"
},
{
    label: "地图查询",
    code: "map"
},
{
    label: "Npc查询",
    code: "npc"
}])
const cutTab = ref('item')
const tabChange = (item: any) => {
    if (item.code == cutTab.value) {
        return
    }
    cutTab.value = item.code;
}
</script>

<style scoped lang="scss">
.header {
    height: 60px;
    background: #20a0ff;
    padding-left: 30px;
    padding-right: 20px;
    .tabs-list {
        height: 60px;
        float: left;
        .tab-item {
            height: 60px;
            line-height: 60px;
            float: left;
            box-sizing: border-box;
            color: #fff;
            padding: 0 20px;
            font-size: 15px;
            cursor: pointer;
            border-radius: 4px;
            position: relative;
            transition: all 0.3s ease;
            &.active::after {
                display: block;
            }
            &::after {
                // color: #409eff;
                content: "";
                position: absolute;
                height: 4px;
                width: 90%;
                left: 5%;
                bottom: 0;
                border-radius: 4px 4px 0 0;
                background: #ff4500;
                display: none;
            }
            &:hover {
                &::after {
                    display: block;
                }
            }
        }
    }
}
</style>

从上面可以看到,Vue 3.0和2.0开发的不同。
3.0支持从上到下一路开发。或者说分段式开发。而不再像2.0需要先定义data什么的,然后再methods里写方法。
3.0其实也是有自己的生命周期的,如有需要可以使用。

beforeCreate ===>setup()
created =======>setup()
beforeMount ===> onBeforeMount
mounted=======> onMounted
beforeUpdate ===> onBeforeUpdate
updated =======> onUpdated
beforeUnmount ==>onBeforeUnmount
unmounted=====> onUnmounted

Demo.vue代码:

<template>
    <h2>当前求和为:{{sum}}</h2>
    <button @click="sum++">点我+1</button>
</template>
<script>
import { ref,onBeforeMount,onMounted,onBeforeUpdate,onBeforeUnmount,onUnmounted } from 'vue'
export default {
    name:'Demo',
    setup(){
        console.log('--setup--')
        //数据
        let sum = ref(0)

        //通过组合式API的形式去使用生命周期钩子
        onBeforeMount(()=>{
            console.log('--onBeforeMount--')
        })
        onMounted(()=>{
            console.log('--onMounted--')
        })
        onBeforeUpdate(()=>{
            console.log('--onBeforeUpdate--')
        })
        onBeforeUnmount(()=>{
            console.log('--onBeforeUnmount--')
        })
        onUnmounted(()=>{
            console.log('--onUnmounted--')
        })
        
        //返回一个对象(常用)
        return { sum }
    },
    //通过配置项的形式使用生命周期钩子
    beforeCreate(){
        console.log('---beforeCreate---')
    },
    created(){
        console.log('--created--')
    },
    beforeMount(){
        console.log('--beforeMount--')
    },
    mounted(){
        console.log('--mounted--')
   } ,
    beforeUpdate(){
        console.log('--beforeUpdate--')
    },
    updated(){
        console.log('--updated--')
    },
    beforeUnmount(){
        console.log('--beforeUnmount--')
    },
    unmounted(){
        console.log('--unmounted--')
    },
    
}
</script>

二 ref、reactive的使用

这里说下大概意思吧,定义字符串、布尔、数字类型用ref,定义对象、数组、数组对象用reactive
使用说明:
· ref定义的数据:操作数据需要.value,读取数据时模版中直接读取不需要.value
· reactive定义的数据:操作数据与读取数据:均不需要.value

let num = ref(0)
let string = ref('测试')
let loading = ref(false);
let user = reactive({
  name:"zs",
  age:18
})
// 使用场景
const changeValue = ()=>{
  num.value = 1;
  string.value = '新值';
  loading.value = true;
  user.age = 19
}
// 这里需要注意的是,如果定义的是数组,要清空或者说重新赋值场景如下
let tableData = reactive([]);
const getList = () => {
  axios....(res => {
    tableData.length = 0;
    Object.assign(tableData, res.data.data.list);
  })
  
}

三、回归正题,新建一个兄弟组件,Content

// components/Content/index.vue
<template>
    <div class="content">content组件</div>
</template>
<script setup lang="ts">
    
</script>
<style scoped lang="scss">
.content {
    box-sizing: border-box;
    height: calc(100% - 60px);
    min-height: 399px;
    padding: 20px 20px 10px;
}
</style>
    

四、 修改App.vue 并且引入该组件

<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import Header from './components/Header/index.vue';
import Content from './components/Content/index.vue';
</script>

<template>
    <Header />
    <Content />
</template>
<style scoped>
</style>

下面看我们看效果


GIF.gif

五、兄弟通讯

5.1 这里我们希望顶部组件切换,内容组件可以获取到。并且根据不同的Code做不同的操作。

修改Header/index.vue,引入onMounted生命周期,以及emit

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

const tabs = reactive([{
    label: "物品查询",
    code: "item"
},
{
    label: "怪物查询",
    code: "mon"
},
{
    label: "地图查询",
    code: "map"
},
{
    label: "Npc查询",
    code: "npc"
}])
const cutTab = ref('');
const emit = defineEmits(['tabChange'])
onMounted(() => {
    tabChange(tabs[0]);
})
const tabChange = (item: any) => {
    if (item.code == cutTab.value) {
        return
    }
    cutTab.value = item.code;
    emit('tabChange', cutTab.value)
}
</script>

5.2 从上面我可以看到他初始化了切换到第一个页签了,并且把当前的code导出去了。

下面我就修改我们的app.vue用于接收它

<template>
    <Header @tabChange="tabChange" />
    <Content />
</template>
<script setup lang="ts">
import Header from './components/Header/index.vue';
import Content from './components/Content/index.vue';
const tabChange = (v: any) => {
    console.log(v)
}
</script>
<style scoped>
</style>

5.3 到这里,我们仅是父组件知道了header的变化。下面怎么告诉Content组件呢?

其实这时候是有2种方法,第一是将code传给Content,Content去监听这个值的变化做对应的处。
方法2就是直接调用Content的方法进行操作。由于是教程,我这里就演示第2种。
修改Content/index.vue

<script setup lang="ts">
import { ref } from 'vue';
let cutTab = ref("");
// 接收到参数后进行你想要的处理
const tabChange = (code: string) => {
    console.log("content:" + code);
    cutTab.value = code;
}
// 导出这个方法
defineExpose({
    tabChange
})
</script>
<style scoped lang="scss">

修改App.vue



<template>
    <Header @tabChange="tabChange" />
    <Content ref="RefContent" />
</template>
<script setup lang="ts">
// 1.0 引入ref
import { ref } from 'vue'
import Header from './components/Header/index.vue';
import Content from './components/Content/index.vue';

// 2.0 要使用子组件就要定义一个变量跟你上面定义的一样的ref
const RefContent: any = ref(null);
const tabChange = (v: any) => {
    // console.log(RefContent)
    RefContent.value.tabChange(v);
}
</script>

看结果:


image.png

结语:

今天这一篇,学习了兄弟通讯,A组件 通过 defineEmits(2.0的$emit)导出方法。B组件通过 defineExpose 将它自身的方法暴露出来供 父组件(Ref) 调用,来达到父子通讯、兄弟通讯。
我们还了解了生命周期,以及ref、reactive的初步使用。

相关文章

  • react 组件通讯的三种方式

    一、父子组件传值 注意:函数组件和类组件是不同的接收方式的 二、子传父通讯 三、兄弟组件通讯

  • vue中组件之间的通信方式?

    vue组件的通讯方式一般分为三类:父子组件,兄弟组件,跨层级组件 父子组件props on ref listene...

  • vue组件的使用

    props和$emit 组件间通讯和自定义事件 父子通讯 props $emit兄弟组件或者隔代组件使用自定义事件...

  • vue组件通信

    1.组建通讯---父子组件通讯 父子通信通过props属性进行传值 父组件 子组件 1.组建通讯---子父组件通讯...

  • Vue中组件通信(eventBus)

    在vue项目中,父子组件间的通讯很方便。但兄弟组件或多层嵌套组件间的通讯,就会比较麻烦。这时,使用eventBus...

  • vue父子通讯

    前言 父子通讯在vue的项目里面有提到过并且也有很细的解释但是还是觉得有必要单独写一个 一、父组件向子组件传递数据...

  • react父子通讯

    父子通讯父传数据给子,子传数据给父 react组件class 组件名 extends React.Componen...

  • VUE父子组件之间的通讯

    VUE父子组件之间的通讯

  • 前端面试必问的

    vue组件通讯的原则 1、父子通讯 props。2、子到父,用自定义事件。非父子组件,就用vuex,就行了

  • 兄弟组件通讯

    eventBus 定义eventBus eventBus的原理是引入一个新的vue对象,分别调用这个对象的事件发布...

网友评论

    本文标题:Vite+vue3+Ts+pinia开发(三:父子通讯、兄弟通讯

    本文链接:https://www.haomeiwen.com/subject/tziwortx.html