|
本帖最后由 lovelilt 于 2022-4-30 10:32 编辑
三、Vue3 组件化及组件通信
1、第一个组件(品类组件) - 使用 setup 及组件API ,自定义封装 Vue3 组件。
- defineProps 用于接收父组件传递过来的自定义属性。
- defineEmits 用于声明父组件传递过来的自定义事件。
- useStore,配合 computed 实现访问 Vuex中的状态数据。
# 文件名 CnCate.vue <template>
<div class='cates'>
<span
v-for='item in cates'
v-text='item.label'
:class='{"on": tab===item.tab}'
@click='change(item.tab)'
>
</span>
</div>
</template>
<script setup>
import { defineProps, defineEmits, computed } from 'vue'
import { useStore } from 'vuex'
// 接收自定义属性
const props = defineProps({
tab: { type: String, default: '' }
})
const emit = defineEmits(['update:tab'])
// 从vuex中访问cates数据
const store = useStore()
const cates = computed(()=>store.state.cnode.cates)
const change = (tab) => {
emit('update:tab', tab) // 向父组件回传数据
}
</script>
<style lang="scss" scoped>
.cates {
padding: 5px 20px;
background-color: rgb(246, 246, 246);
}
.cates span {
display: inline-block; height: 24px;
line-height: 24px; margin-right: 25px;
color: rgb(128, 189, 1); font-size: 14px;
padding: 0 10px; cursor: pointer;
}
.cates span.on {
background-color: rgb(128, 189, 1);
color: white; border-radius: 3px;
}
</style>
2、第二个组件(分页组件) - 使用 toRefs 把 props 变成响应式的。在Vue3中,默认情况下 props是不具备响应式的,即父组件中的数据更新了,在子组件中却是不更新的。
- 使用 computed 实现动态页码结构的变化。
- defineProps、defineEmits,分别用于接收父组件传递过来的自定义属性、自定义事件。
# 文件名 CnPage.vue
<template>
<div class='pages'>
<span @click='prev'><<</span>
<span v-if='page>3'>...</span>
<span
v-for='i in pages'
v-text='i'
:class='{"on":i===page}'
@click='emit("update:page", i)'
>
</span>
<span>...</span>
<span @click='emit("update:page", page+1)'>>></span>
</div>
</template>
<script setup>
import { defineProps, defineEmits, computed, toRefs } from 'vue'
let props = defineProps({
page: { type: Number, default: 1 }
})
const { page } = toRefs(props)
const emit = defineEmits(['update:page'])
const pages = computed(()=>{
// 1 1 2 3 4 5 ...
// 2 1 2 3 4 5 ...
// 3 1 2 3 4 5 ...
// 4 ... 2 3 4 5 6 ...
// n ... n-2 n-1 n n+1 n+2 ...
const v = page.value
return v<=3 ? [1,2,3,4,5] : [v-2,v-1,v,v+1,v+2]
})
const prev = () => {
if (page.value===1) alert('已经是第一页了')
else emit('update:page', page.value-1)
}
</script>
<style lang="scss" scoped>
.pages {
line-height: 50px; text-align: right;
}
.pages>span {
cursor: pointer; display: inline-block;
width: 34px; height: 30px; margin: 0;
line-height: 30px; text-align: center;
font-size: 12px; border: 1px solid #ccc;
}
.pages>span.on {
background: rgb(128, 189, 1); color: white;
}
</style>
3、在父级组件中使用 自定义组件 - v-model:tab='tab' 是 :tab 和 @update:tab 的语法糖简写;
- v-model:page='page' 是 :page 和 @update:page 的语法糖简写;
- 使用 watch 监听品类和页面的变化,然后触发调接口获取新数据。
# 文件名 Cnode.vue
<template>
<div class='app'>
<!-- <CnCate :tab='tab' @update:tab='tab=$event' /> -->
<CnCate v-model:tab='tab' />
<!-- <CnPage :page='page' @update:page='page=$event' /> -->
<CnPage v-model:page='page' />
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import CnCate from './components/CnCate.vue'
import CnPage from './components/CnPage.vue'
const tab = ref('')
const page = ref(1)
const stop = watch([tab, page], ()=>{
console.log('当品类或页码变化时,调接口')
})
</script>
|
|