JSX
JSX是一种JavaScript的语法扩展,运用于React架构中,其格式比较像是模版语言,但事实上完全是在JavaScript内部实现的。元素是构成React应用的最小单位,JSX就是用来声明React当中的元素,React使用JSX来描述用户界面。
1. 变量作用域比较
1.1 .vue 中无法使用当前作用域变量,必须return后才能使用
// Scope.vue
<template>
<div>{{ state.count }}</div>
<button @click="handleClick">点击加1</button>
</template>
<script>
import { reactive } from "vue";
export default {
setup() {
let state = reactive({ count: 0 });
function handleClick() {
state.count++;
}
// 在模板中无法直接使用setup中的变量,必须return
return { state, handleClick };
},
};
</script>
1.2 .jsx 中可以直接使用当前作用域的变量
// Scope.jsx
// 使用babel插件写法
import { reactive } from "vue";
export default {
setup() {
let state = reactive({
count: 0
});
function handleClick() {
state.count++;
}
// 可以在渲染函数中直接使用当前作用域的变量
return ()=>(
<div>
<div >{ state.count }</div>
<button onClick={handleClick}>点击加1</button>
</div>
)
},
};
// Scope.jsx
// 不使用babel插件写法
<script>
export default {
name: "test",
data() {
return {};
},
methods: {},
render(createElement) {
return createElement("h1", "abc");
},
};
</script>
2. 灵活性比较
2.1 .vue 中一个文件只能写一个组件
// NoMulti.vue
<template>
<Title :title="state.title" />
</template>
<script>
import { reactive } from "vue";
// 不能在一个.vue中写多个组件,必须将 Title 写在另外一个文件中
import Title from "./Title.vue";
export default {
components: { Title },
setup() {
let state = reactive({ title: "jsv-compiler" });
return { state };
},
};
</script>
// Title.vue
<template>
<h1>hello {{title}}</h1>
</template>
<script>
export default {
props: {
title: String
}
}
</script>
2.2. .jsx 中可以写多个组件
import { reactive } from "vue";
export default {
setup() {
let state = reactive({
title: 'jsv-compiler'
});
// 一个文件中可以写多个组件
let Title = ()=><h1>hello {state.title}</h1>
return ()=>(
<div>
<Title />
</div>
)
},
};
3. 指令比较
3.1. .vue 原生支持优雅的指令写法
<A v-model:argument.modifer="val" />
3.2. .jsx 本身不支持指令 社区有多种指令的书写方式,各种千奇百怪,为此还开了issue讨论,至今仍然没有友好的解决方式。因此可以暂时认为 .jsx 不支持指令或支持的不好.
<A v-model={[val, 'argument', ['modifier']]} />
4. 运行时性能比较
4.1. .vue 支持hoist,block,patchProps等运行时性能提升,至少比 .jsx 性能快了3倍
// 编译前
<div>
<div>静态节点</div>
<div >{{state.count }}</div>
</div>
// 编译后
const { createVNode: _createVNode, toDisplayString: _toDisplayString, openBlock: _openBlock, createBlock: _createBlock } = Vue
const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "静态节点", -1 /* HOISTED */)
// render 函数 上面的代码只会执行一次
// 每次重新渲染都再次执行 render 函数
// 1. 关于 _hoisted_1 静态节点变量提升,作用是再次执行render函数时,不用重新创建节点,直接从内存中读取;
// 2. 关于 _openBlock, _createBlock,作用是在 dom-diff 时,不比较静态节点,只比较可变节点;
// 3. 关于 patchProps,作用是在 dom-diff 时,只比较 text 的变化,不比较其他任何属性的变化;
return function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_hoisted_1, // 静态节点变量提升
_createVNode("div", null, _toDisplayString(_ctx.state.count), 1 /* TEXT */) // 此处的 1 用于 patchProps 的标识
]))
}
// Check the console for the AST
4.2. .jsx 没有运行时优化
// 编译前
<div>
<div >static node</div>
<div >{ state.count }</div>
</div>
// 编译后 (使用 vite 工具编译)
jsx(
"div",
null /* @__PURE__ */,
jsx("div", null, "static node") /* @__PURE__ */,
jsx("div", null, state.count)
)
5. 生态比较
5.1. 当前知名的UI库比如 ant-desing-vue,vant 内部采用了 jsx
5.2. 但对外提供的组件仍然是 vue的模板语法。对于使用者如果要用 jsx,还得自己把 vue 改成 jsx,代价高昂呀
JSV
1.使用实例
// 文件命名为 App.jsv
import { reactive } from "vue";
export default {
name: "App",
setup() {
let state = reactive({
title: 'jsv-compiler',
count: 0
});
function handleClick() {
state.count++;
}
// 一个文件中写多个组件。此处的 Title 是 组件。
let Title = <template><h1>hello {{state.title}}</h1></template>
// 直接使用当前作用域的变量,比如 state.count
return (
<template>
<Title />
<div>{{ state.count }}</div>
<button @click="handleClick">点击加1</button>
</template>
)
},
};
2. 安装依赖包
npm i -D jsv-compiler
3. 配置插件
import {jsvPlugin} from 'jsv-compiler'
export default {
configureServer: [jsvPlugin]
}
4. 语法高亮
4.1 在vscode的插件市场中下载插件: jsv
4.2 因为是第一个版本,在 App.jsv 中暂时无法语法高亮,需将文件名改为 App.js ,并在template 旁边加上反引号 才能在vscode中实现语法高亮,实际在编译层面是不需要加反引号的。
亲测
代码:
<script>
export default {
name: "hooks",
data() {
return {
count: 0,
};
},
methods: {
onChange(val) {
this.count = val;
},
},
render() {
const { count, onChange } = this;
return <div>123</div>;
},
};
</script>
在vue3.0中使用jsx
<script>
import { render, ref, reactive, defineComponent } from "vue";
export default defineComponent({
name: "HelloWorld",
props: {
msg: String,
},
setup() {
let state = reactive({ count: 0 });
// 2. 用 ref 函数包装一个响应式变量 number
let number = ref(0);
// 3. 设定一个方法
let add = (a) => {
console.log(number.value);
// number是被ref函数包装过了的,其值保存在.value中
number.value++;
};
function handleClick(h) {
debugger;
state.count++;
}
// 4. 将 number 和 add 返回出去,供template中使用
return { number, state, add, handleClick };
// return () => (
// <div class="hello">
// <div>
// <p>Number:{number}</p>
// <button style="margin-left: 5px;" onClick={() => add}>
// 点击
// </button>
// </div>
// <div style="margin-top: 5px;">
// <p>State:{state.count}</p>
// <button style="margin-left: 5px;" onClick={() => handleClick}>
// 点击
// </button>
// </div>
// </div>
// );
onBeforeMount(() => {
// 在挂载前执行某些代码
});
onMounted(() => {
// 在挂载后执行某些代码
});
onBeforeUpdate(() => {
// 在更新前前执行某些代码
});
onUpdated(() => {
// 在更新后执行某些代码
});
onBeforeUnmount(() => {
// 在组件销毁前执行某些代码
});
unMounted(() => {
// 在组件销毁后执行某些代码
});
},
render() {
return (
<div class="hello">
<h1>{this.msg}</h1>
<div>
<p>Number:{this.number}</p>
<button style="margin-left: 5px;" onClick={(a) => this.add()}>
点击
</button>
</div>
<div style="margin-top: 5px;">
<p>State:{this.state.count}</p>
<button style="margin-left: 5px;" onClick={() => this.handleClick('h')}>
点击
</button>
</div>
</div>
);
},
});
</script>
jsx使用心得
1.在jsx中使用for循环实现类似于v-for的效果
<div>
{this.doneTodos1.map((element) => {
return (
<div>
{element.id} -- {element.text}
</div>
);
})}
</div>
2.在jsx中添加点击事件,使用方式
在onClick中需要写成箭头函数的形式,不然就会自持行
<button class="button" onClick={() => this.increment(3)}>
按钮
</button>
链接: https://www.jb51.net/article/171241.htm.