Vite+vue3+Ts+pinia开发(章节三)

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

初始目录:

一、在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>

下面看我们看效果

五、兄弟通讯

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>

看结果:

结语:

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

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值