Vue3 + TS 开发前端组件库 丨走进 JSX

801 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

Vue3 + TS 开发前端组件库 丨走进 JSX

如何用 ts 在 vue3 中定义组件?

如何提取 props 定义?

vue 中 h 函数是什么?

setup 的运用和其意义

setup 如何返回 render 函数?

如何使用 jsx 开发 vue3 组件?

一步步走向 JSX

如何用 ts 在 vue3 中定义组件?

Component 接口

defineComponent 函数 定义组件 (ts 中必须使用, 它返回组件的定义)

import { defineComponent, PropType } from 'vue'

interface Config {
  name: string
}
export default defineComponent({
  name: 'App',
  props: {
    age: {
      type: Number as PropType<number>
    },
    config: {
      type: Object as PropType<Config>,
      required: true
    }
  },
  components: {},
  ...
})

如何提取 props 定义?

import { defineComponent } from 'vue'

const PropsType = {
  msg: String,
  age: {
    type: Number,
    required: true,
  },
} as const // 声明 props 是只读Readonly的对象

export default defineComponent({
  name: 'HelloWorld',
  props: PropsType,
  mounted() {
    this.age
  },
})

vue 中 h 函数是什么?

SFC 是怎么运作的?

h 函数是 createVNode 的简单的封装

import { createApp, defineComponent, h } from 'vue'
import HelloWorld from './components/HelloWorld.vue'
const img = require('./assets/logo.png') //eslint-disable-line

const App = defineComponent({
  render() {
    // h 相当于 createElement
    // h (节点名称, 节点属性, 子类)
    return h('div', { id: 'app' }, [
      h('img', {
        alt: 'Vue logo',
        src: img,
      }),
      h(HelloWorld, {
        msg: 'Welcome to your Vue.js + TypeScript App',
        age: 12,
      }),
    ])
  },
})

createApp(App).mount('#app')

setup 的运用

export default defineComponent({
  name: 'App',
  setup(props, { slots, attrs, emit }) {
    const state = reactive({
      name: 'dmw',
    })
    setInterval(() => {
      state.name += 1
    }, 1000)
    
    // 初始化监听并且改变的时候也会监听
    watchEffect(() => {
      console.log(state.name)
    })
     watch([xxxx, xxxx, (n, o) => { 
      console.log(n);
      console.log(o);
      document.title = n[0];
    },{
        deep: true,
        immediate:true
      });
    }
    return {
      ...toRefs(state),
    }
  },
})

// watch 与 watchEffect 的区别
// watch监听,可以以数组的形式监听,没有初始化监听,可加属性immediate deep ,
// 初始化监听并且改变的时候也会监听

setup 如何返回 render 函数?

import { createApp, defineComponent, h, reactive, ref } from 'vue'
// import App from './App.vue'
import HelloWorld from './components/HelloWorld.vue'
const img = require('./assets/logo.png') //eslint-disable-line

const App = defineComponent({
  setup() {
    const state = reactive({
      name: 'dmw',
    })
    const numberRef = ref(1)
    setInterval(() => {
      state.name += 1
      numberRef.value += 1
    }, 2000)
    return () => {
      return h('div', { id: 'app' }, [
        h('img', {
          alt: 'Vue logo',
          src: img,
        }),
        h('p', numberRef.value),
        h(HelloWorld, {
          msg: state.name,
          age: 12,
        }),
      ])
    }
  },
})

createApp(App).mount('#app')

如何使用 jsx 开发 vue3 组件?

Vite 安装配置 vue3-jsx支持依赖

安装 vue-jsx 支持

yarn add @vitejs/plugin-vue-jsx -D

配置 vue-jsx 插件

// vim vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 引入 jsx 依赖
import vueJsx from '@vitejs/plugin-vue-jsx'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),// 使用 vue-jsx
  ]
})

Webpack 安装配置 vue3-jsx 依赖

npm install @vue/babel-plugin-jsx -D
// babel.config.js
{
	"plugins": ["@vue/babel-plugin-jsx"]
}

JSX 起步

修改 main.ts

import { createApp } from 'vue'

import App from './App'

createApp(App).mount('#app')

在 src 目录下新建 App.tsx

import { createApp, defineComponent, h, reactive, ref } from 'vue'
const img = require('./assets/logo.png') //eslint-disable-line
import HelloWorld from './components/HelloWorld.vue'
function renderHelloWorld(age: number) {
  return <HelloWorld age={age}></HelloWorld>
}
export default defineComponent({
  setup() {
    const state = reactive({
      name: 'dmw',
    })
    const numberRef = ref(1)
    // setInterval(() => {
    //   state.name += 1
    //   numberRef.value += 1
    // }, 2000)
    return () => {
      return (
        <div id="app">
          <img src={img} alt="" />
          <p>{state.name + numberRef.value}</p>
          {renderHelloWorld(18)}
        </div>
      )
    }
  },
})

image-20211004024729112.png