jsx与template
无论是react还是vue,实质的生产环境打包产物(运行时)是不存在jsx或template文件的,它们在编译时会被处理成对应的render函数,作为种子在客户端渲染成页面。
jsx和template的存在都是为了开发者便捷编写视图代码(直接写render函数过于繁琐)。相比template,jsx有如下优点:
- JavaScript的表达能力: JSX 是 JavaScript 的扩展,因此你可以在 JSX 中使用 JavaScript 的所有功能。这意味着你可以在 JSX 中使用条件语句、循环、变量,以及其他 JavaScript 的高级特性。这种灵活性可以使得在 UI 描述中更容易实现复杂的逻辑。
- 更接近 JavaScript: 对于熟悉 JavaScript 的开发者来说,JSX 更接近他们的编程语言,因为它实际上就是 JavaScript 的语法扩展。这使得学习曲线相对较低,并且更容易理解。
- 组件内逻辑和渲染在一起: 在 JSX 中,组件的逻辑和渲染通常在同一个文件中,使得组件的代码更加紧凑和易于维护。
- 更强大的生态系统: React 生态系统是非常庞大且活跃的,JSX 作为 React 的一部分,受益于 React 生态系统的丰富资源和社区支持。
在vue3中使用jsx
创建组件
javascript
import { defineComponent } from "vue";
export default defineComponent({
setup() {
return () => <div>Hello</div>;
}
});
嵌入动态值
在jsx中使用动态值,在vue中我们使用双括号,这里使用单括号。
ps:如果使用ref必须加.value取值。
javascript
//test.js
import { defineComponent, ref, reactive } from "vue";
export default defineComponent({
props: ["text"],
setup(props) {
let num = ref(1);
let article = reactive({ text: "hi" });
return () => (
<div>
<div>{num.value}</div>
<div>{article.text}</div>
<div>{props.text}</div>
</div>
);
}
});
//main.js
import { createApp, defineComponent } from "vue";
import test from "./components/test";
const App = defineComponent({
setup() {
return () => <test text={"你好"} />;
}
});
createApp(App).mount("#app");
实现v-if v-for功能
你可以将jsx中的标签视作一定程度上的js类型数据,它可以参与三元运算,作为参数返回,作为数组的组成元素等。正因为如此,jsx不需要v-if指令实现视图条件展示,通过js条件语句直接进行判断返回对应视图渲染即可,通过工厂函数我们可以获得比template更好的代码可读性。
ps:在jsx中使用js运行语句需要使用大括号包裹。
javascript
setup() {
function factory(id) {
switch (id) {
case 1:
return <div>一</div>;
case 2:
return <div>二</div>;
}
}
let ok = ref(false);
return () => (
<div>
<div>{ok.value ? <div>yes</div> : <span>no</span>}</div>
<div>{factory(2)}</div>
</div>
);
}
当遇到jsx类型元素的数组时,会自动循环渲染到页面
javascript
setup() {
const arr = ref([<div>1</div>, <div>2</div>]);
return () => <div>{arr.value}</div>;
}
利用这个特性我们可以结合map函数这样做,这样就实现了v-for:
javascript
setup() {
const arr = ref([
{ id: 1, name: "tsz" },
{ id: 2, name: "jsx" }
]);
return () => (
<div>
{arr.value.map((e) => {
return (
<div>
<span style="color:red">{e.id}</span>
<span>{e.name}</span>
</div>
);
})}
</div>
);
}
实现v-bind v-on功能
属性绑定也是使用大括号包裹
javascript
setup() {
const href = ref("https://www.bing.com/");
return () => <a href={href.value}>DevUI Design</a>;
}
以 on 开头,并跟着大写字母的 props 会被当作事件监听器。比如,onClick 与模板中的 @click 等价。
javascript
setup() {
return () => (
<button
onClick={(event) => {
/* ... */
}}
>
click me
</button>
);
}
事件修饰符设置
对于 .passive、.capture 和 .once 事件修饰符,使用驼峰写法将他们拼接在事件名后面:
ini
setup() {
return () => (
<input
onClickCapture={() => {}}
onKeyupOnce={() => {}}
onMouseoverOnceCapture={() => {}}
/>
);
}
实现插槽功能
javascript
setup(props, { slots }) {
let inerdata=ref('来源')
return () => (
<div>
<div>{slots.title?.()}</div>
<div>{slots.default?.()}</div>
<div>{slots.footer?.(inerdata.value)}</div>
</div>
);
}
使用插槽相对比较麻烦,我这里推荐 传递一个配置对象 的方式
javascript
import { createApp, defineComponent } from "vue";
import test from "./components/test";
const App = defineComponent({
setup() {
return () => (
<test>
<div>233</div>
</test>
);
}
});
createApp(App).mount("#app");
javascript
setup() {
return () => (
<test>
{{
default: () => <div>水水水水水水水水水水水水水</div>,
title: () => <h1>我的祖国</h1>,
footer: (inerdata) => <h6>{inerdata}:来自网络</h6>
}}
</test>
);
}
v-model
jsx是支持v-model语法的,需要注意的是与事件绑定不同,指令的修饰符是可以像template加在其后
javascript
// 正常写法
<input v-model="value" /> // vue
<input v-model={value} /> // jsx
// 指定绑定值写法
<input v-model:modelValue="value" /> // vue
<input v-model={[value,'modelValue']} /> // jsx
// 修饰符写法
<input v-model:modelValue.trim="value" /> // vue
<input v-model={[value,'modelValue',['trim']]} /> // jsx
扩展:在template中混杂 函数式组件
函数式组件是一种定义自身没有任何状态的组件的方式。它们很像纯函数:接收 props,返回 vnodes。函数式组件在渲染过程中不会创建组件实例 (也就是说,没有 this),也不会触发常规的组件生命周期钩子。
我们可以在模板(SFC)文件中定义后直接使用,在一些特定场景中比较实用。
xml
<template>
<MyComponent :value="23" @print="print" />
</template>
<script setup lang="jsx">
// import { ref } from 'vue';
function print(e){console.log(e);}
function MyComponent(props, { slots, emit, attrs }) {
return (
<div>
<div>{props.value}</div>
<button onClick={()=>{emit('print',233)}}/>
</div>
);
}
MyComponent.props = ['value']
MyComponent.emits = ['print']
</script>