不强制要求组件有根节点
// vue2
<template>
<div>
<h1>标题</h1>
<p>内容</p>
</div>
</template>
// vue3
<template>
<h1>标题</h1>
<p>内容</p>
</template>
注意事项
虽然 Vue 3 不再强制要求根节点,但在某些情况下,你可能仍然需要使用一个包裹元素。例如:
CSS 样式:如果你需要对整个组件应用统一的样式,使用一个包裹元素会更方便。
事件监听:如果你需要在组件级别添加事件监听器(如点击事件),使用一个包裹元素会更合适。
props值使用
this.bannerData → props.bannerData
// Options API
props: {
bannerData: {
type: Object,
default: () => ({})
}
}
bannerDataComputed() {
return {
...this.bannerData,
json: BANNER_JSON
}
}
//Composition API
const props = withDefaults(defineProps<{ bannerData: any }>(), {
bannerData: ()=> ({})
})
const bannerDataComputed = computed(()=>{
return {
...props.bannerData,
json: BANNER_JSON
}
})
computed值使用
this.bannerDataComputed → bannerDataComputed.value
// Options API
bannerDataComputed() {
return {
...this.bannerData,
json: BANNER_JSON
}
},
staticData() {
return this.bannerDataComputed.json || {}
},
// Composition API
const bannerDataComputed = computed(()=>{
return {
...props.bannerData,
json: BANNER_JSON
}
})
const staticData = computed(()=>{
return bannerDataComputed.value.json || {}
})
methods编写
// Options API
methods: {
jumpPage() {
if (!this.bannerData?.jumpUrl) return
this.$emit('jumpPage', this.bannerData.jumpUrl)
}
}
// Composition API
const jumpPage = () => {
if (!props.bannerData?.jumpUrl) return
emit('jumpPage', props.bannerData.jumpUrl)
}
自动解析机制
在vue2中,父组件引入子组件,操作步骤如下:
- 引入子组件
- 注册子组件
- 使用子组件
在vue3中,由于自动解析机制,可以省略显示注册子组件的需要,操作步骤如下:
- 引入子组件
- 使用子组件
// vue2
<BannerCard v-for="(item, idx) in cardList" :key="idx" :card-data="item" :index="idx" :static-data="staticData" />
import BannerCard from './BannerCard.vue'
components: {
BannerCard
}
// vue3
<BannerCard v-for="(item, idx) in cardList" :key="idx" :card-data="item" :index="idx" :static-data="staticData" />
import BannerCard from './BannerCard.vue'
注意事项
虽然 Vue 3 的自动解析机制在大多数情况下可以正常工作,但在某些复杂场景下,显式注册组件仍然是推荐的做法。例如:
组件名称冲突:如果多个组件的名称相同,自动解析机制可能会导致混淆。
动态组件:如果你需要动态加载组件,显式注册会更加清晰和可控。
代码可读性:显式注册组件可以提高代码的可读性和可维护性,特别是对于大型项目。
emit
// Options API
jumpPage() {
this.$emit('jumpPage', this.bannerData.jumpUrl)
}
// Composition API
const emit = defineEmits(['jumpPage']);
const jumpPage = () => {
emit('jumpPage', this.bannerData.jumpUrl)
}
ref使用
// -----------Options API-------------
<div ref="bannerContent" class="content"></div>
mounted() {
this.handleTouchMove = (e) => {
e.stopPropagation()
}
this.handleTouchStart = (e) => {
e.stopPropagation()
}
this.$refs.bannerContent.addEventListener('touchmove', this.handleTouchMove)
this.$refs.bannerContent.addEventListener('touchstart', this.handleTouchStart)
},
beforeDestroy() {
this.$refs.bannerContent.removeEventListener('touchmove', this.handleTouchMove)
this.$refs.bannerContent.removeEventListener('touchstart', this.handleTouchStart)
}
// --------------Composition API------------
<div ref="bannerContent" class="content"></div>
// 定义一个响应式引用,指向模板中的 bannerContent
const bannerContent = ref()
// 定义事件处理函数
const handleTouchMove = (e) => {
e.stopPropagation()
}
const handleTouchStart = (e) => {
e.stopPropagation()
}
onMounted(()=>{
bannerContent.value.addEventListener('touchmove', handleTouchMove)
bannerContent.value.addEventListener('touchstart', handleTouchStart)
})
onBeforeUnmount(()=>{
bannerContent.value.removeEventListener('touchmove', handleTouchMove)
bannerContent.value.removeEventListener('touchstart', handleTouchStart)
})
::v-deep
在 Vue 3 中,::v-deep
作为组合选择器已被弃用。你应该使用 :deep()
伪类选择器来替代它。这种变化主要是为了更好地与 CSS 标准保持一致,并且提供更清晰的语法。
beforeDestroy
在 Vue 3 中,生命周期钩子 beforeDestroy
已经被重命名为 beforeUnmount
。这是为了更好地反映组件的生命周期阶段,并使命名更加一致。
- Options API:直接使用
beforeUnmount
。 - Composition API:使用
onBeforeUnmount
。