純js實現 vue 元件 與 vue 單檔案元件對比

HorseShoe2016發表於2024-04-10

vue 的單檔案元件,其實最終是編譯成了一個 object,然後呼叫該 object 上的 setup() 函式來渲染頁面的;
如下兩個頁面,一個使用 vue 單檔案元件的語法來實現,一個使用純 js 來實現,二者效果一致


使用 vue 實現元件

src/views/VueImplementedView.vue

<template>
  <div>
    <h1 class="text-blue-500 text-lg text-center">{{ name }}</h1>
    <ul
      class="text-center space-y-1 border-2 border-green-200 p-2 rounded-lg"
      @dragstart="dragToggle"
      @dragend="dragToggle"
    >
      <li
        v-for="i in 10"
        :key="i"
        class="border-2 border-red-200 rounded-full bg-cyan-200"
        draggable="true"
      >
        item-{{ i }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { defineProps } from 'vue'
defineProps({
  name: {
    type: String,
    default: 'This is VueImplementedView'
  }
})

function dragToggle(event) {
  const ele = event.target
  ele.classList.toggle('text-red-500')
  ele.classList.toggle('text-4xl')
  ele.classList.toggle('font-bold')
}
</script>

使用 js 實現元件

src/views/JSImplementedView.js

import { h } from 'vue'

const component = {
  setup(props) {
    function dragToggle(event) {
      const ele = event.target
      ele.classList.toggle('text-red-500')
      ele.classList.toggle('text-4xl')
      ele.classList.toggle('font-bold')
    }
    const render = () => {
      const list = []
      for (let i = 0; i < 10; i++) {
        list.push(
          h(
            'li',
            {
              class: 'border-2 border-red-200 rounded-full bg-cyan-200',
              key: i,
              draggable: true
            },
            `item-${i}`
          )
        )
      }
      const ul = h(
        'ul',
        {
          class: 'text-center space-y-1 border-2 border-green-200 p-2 rounded-lg',
          onDragstart: dragToggle,
          onDragend: dragToggle
        },
        list
      )
      const h1 = h('h1', { class: 'text-blue-500 text-lg text-center' }, `${props.name}`)
      return h('div', [h1, ul])
    }
    return render
  },
  props: {
    name: {
      type: String,
      default: 'This is a JSImplementedView'
    }
  }
}

export default component

在 router 中引用這兩個元件

src/router/index.js

import { createRouter, createWebHistory } from 'vue-router'
import JSImplementedView from '@/views/JSImplementedView.js'
import VueImplementedView from '@/views/VueImplementedView.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/js-implemented-view',
      name: 'JSImplementedView',
      component: JSImplementedView,
      props: {
        name: 'Hello, this is JSImplementedView'
      }
    },
    {
      path: '/vue-implemented-view',
      name: 'VueImplementedView',
      component: VueImplementedView,
      props: {
        name: 'Hello, this is VueImplementedView'
      }
    }
  ]
})

export default router

效果

二者效果一致:


這裡可以觀察到: v-for="i in 10"i 的起始值是 1 而不是 0

相關文章