vue3 defineComponent: 使用纯 Javascript 定义组件

vuejs 官方文档参考:
definecomponent
渲染函数 API: h()

可以通过向 defineComponent() 传入一个 组合式 APIsetup function,或者 选项式 APIexport object,来定义一个组件,并包含各种响应式功能;如下 HomeAbout 组件所示:

<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 页面的文字,可以切换文字颜色:

posted @ 2024-03-24 19:18  HorseShoe2016  阅读(124)  评论(0编辑  收藏  举报