VUE3模板,JSX,JSV

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.

总结

good morning
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值