vue3 defineComponent: 使用纯 Javascript 定义组件
vuejs 官方文档参考:
definecomponent
渲染函数 API: h()
可以通过向 defineComponent() 传入一个 组合式 API
的 setup function
,或者 选项式 API
的 export object
,来定义一个组件,并包含各种响应式功能;如下 Home
和 About
组件所示:
<script setup>
import { ref, computed, defineComponent, h } from 'vue'
// 使用 `组合式 API` 的方式调用 defineComponent
const Home = defineComponent(
(props) => {
const colorIndex = ref(0)
const colors = [
// tailwindcss class
'text-red-500',
'text-green-500',
'text-blue-500',
'text-orange-500',
'text-purple-500'
]
function changeColor() {
const oldIndex = colorIndex.value
while (oldIndex == colorIndex.value) {
colorIndex.value = Math.floor(Math.random() * colors.length)
}
}
// 每次点击文字,会 call changeColor(), 从而导致 colorIndex 的 subscriber ---- render 的执行
const render = () => {
return h(
'h1',
{ onClick: changeColor, class: colors[colorIndex.value] },
`Hi ${props.name}, This is Home Page, click to change the text color`
)
}
return render
},
{
props: { name: { type: String, default: 'Alice' } }
}
)
// 使用 `选项式 API` 的方式调用 defineComponent
const About = defineComponent({
template: `<h1 @click="changeColor" :class="colors[colorIndex]">{{value}}</h1>`,
data() {
return {
value: `Hello ${this.name}, This is About Page, click to change the text color`,
colors: [
// tailwindcss class
'text-red-500',
'text-green-500',
'text-blue-500',
'text-orange-500',
'text-purple-500'
],
colorIndex: 0
}
},
props: {
name: {
type: String,
default: 'Bob'
}
},
methods: {
changeColor() {
const oldIndex = this.colorIndex
while (oldIndex == this.colorIndex) {
this.colorIndex = Math.floor(Math.random() * this.colors.length)
}
}
},
mounted() {
// 由于 <keep-alive></keep-alive>的作用,使得页面切换时不销毁,所以 mounted() 只调用一次
this.colorIndex = Math.floor(Math.random() * this.colors.length)
}
})
const NotFound = defineComponent({
template: `<h1>404</h1>`
})
const routes = {
'/': Home,
'/about': About
}
const currentPath = ref(window.location.hash)
window.addEventListener('hashchange', () => {
currentPath.value = window.location.hash
})
const currentView = computed(() => {
return routes[currentPath.value.slice(1) || '/'] || NotFound
})
</script>
<template>
<div>
<ul class="list-none flex justify-start space-x-5">
<li><a href="#/">Home</a></li>
<li><a href="#/about">About</a></li>
<li><a href="#/non-existent-path">Broken Link</a></li>
</ul>
<keep-alive>
<component :is="currentView" />
</keep-alive>
</div>
</template>
<style scoped>
li a {
color: cornflowerblue;
}
h1 {
font-size: 2em;
font-weight: bold;
}
</style>
点击 Home
/ About
页面的文字,可以切换文字颜色: