类似React,其实Vue也是支持JSX和渲染函数的,在Vue中使用这些功能可以发挥JavaScript的全部编程能力。
基本用法
Vue中提供了h函数用于创建虚拟节点并创建组件,这样的组件里面就不用写模板,后缀应该为js。和vue里的script标签一样,默认导出一个js对象:
1 2 3 4 5
| import { h } from "vue";
export default function App() { return h("h1", "Hello World"); }
|
然后在main.js中引入并挂载:
1 2 3 4
| import { createApp } from 'vue'; import App from './App.js';
createApp(App).mount('#app');
|
这时页面已经可以正常显示了。
h函数在此前Vue的虚拟DOM原理中尝试实现过,是一个十分灵活的函数,接收三个参数,第一个参数是要创建的虚拟节点的标签名,第二个是虚拟节点的class、id、事件等属性,第三个是子节点。
返回渲染函数
使用渲染函数也可以使用组合式API,只要在导出的js对象中写setup函数就好了,而这时setup函数返回的内容不应该是在模板中要使用的变量,而是渲染函数:
1 2 3 4 5 6 7
| import { h } from "vue";
export default { setup() { return () => h("h1", "Hello World"); } }
|
setup中返回的渲染函数能正常访问到setup中的props、响应式变量等。
JSX
Vue中也支持使用JSX,在使用JSX之前,要做一点配置,这里使用的是vite环境:
首先要安装vite的vueJsx插件:
1
| $ npm i @vitejs/plugin-vue-jsx
|
然后在vite.config.js中启用它:
1 2 3 4 5 6 7
| import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import vueJsx from '@vitejs/plugin-vue-jsx';
export default defineConfig({ plugins: [vue(), vueJsx()] });
|
现在可以正常使用JSX了,上面的示例中,将App.js文件后缀改成jsx,修改文件内容为:
1 2 3 4 5 6 7 8
| import { h } from "vue";
export default { setup() { return () => <h1>Hello World</h1>; } }
|
一些例子
v-if
模板实现
1 2 3 4 5 6 7 8 9
| <template> <div v-if="ok">OK</div> <div v-else>NO</div> </template>
<script setup> import { ref } from "vue"; var ok = ref(true); </script>
|
JSX/渲染函数实现
1 2 3 4 5 6
| export default { setup() { var ok = true; return () => ok ? <h1>OK</h1> : <h1>NO</h1>; } }
|
1 2 3 4 5 6 7 8
| import { h } from 'vue';
export default { setup() { var ok = true; return () => ok ? h("h1", "ok") : h("h1", "no"); } }
|
v-for
模板实现
1 2 3 4 5 6 7 8 9 10 11 12
| <template> <ul> <li v-for="item in items"> {{ item }} </li> </ul> </template>
<script setup> import { reactive } from "vue"; var items = reactive([1, 2, 3, 4, 5]); </script>
|
JSX/渲染函数实现
1 2 3 4 5 6 7 8 9
| export default { setup() { var items = [1, 2, 3, 4, 5]; return () => <ul> {items.map((v) => <li>{v}</li>)} </ul>; } }
|
1 2 3 4 5 6
| export default { setup() { var items = [1, 2, 3, 4, 5]; return () => h("ul", items.map(v => h("li", v))); } }
|
v-on
模板实现
1 2 3 4 5 6 7 8 9 10 11
| <template> <button @click=" () => { console.log(1); } " > test </button> </template>
|
JSX/渲染函数实现
1 2 3 4 5
| export default { setup() { return () => <button onClick={(v) => { console.log(v) }}>test</button>; } }
|
1 2 3 4 5 6 7
| import { h } from 'vue';
export default { setup() { return () => h("button", { onClick: (e) => { console.log(e); } }, "test") } }
|
组件
JSX和h函数同样可以支持渲染组件:
1 2 3 4 5 6 7 8
| import { h } from 'vue';
export default { setup() { return () => h("h1", "Hello World"); } }
|
1 2 3 4 5 6 7 8 9
| import { h } from "vue"; import test from "./components/test";
export default { setup() { return () => h(test); } }
|
1 2 3 4 5 6 7 8
| import Test from "./components/test";
export default { setup() { return () => <Test />; } }
|
效果是一模一样的。如果要更简单一点,也可以像下面这样:
1 2 3 4 5
| import Test from "./components/test";
export default function App() { return <Test />; }
|
效果也是一模一样的。
实现计数器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import { ref, h } from 'vue'
export default { setup() { var count = ref(0); var add = () => { console.log(count.value) count.value++; } return () => ( <div> <div class="count">{count.value}</div> <button onClick={add}>add</button> </div> ) return () => h("div", [ h("div", count.value), h("button", { onClick: add }, "add") ]) } }
|
函数式组件
函数式组件是一种定义自身没有任何状态的组件的方式。在函数式组件里定义ref、reactive等响应性的变量都是不会起作用的。函数式组件适合做那种状态不会改变的组件。例如:
1 2 3
| export default function () { return <h1>Hello World</h1> }
|