vue中正确使用jsx语法的姿势分享

2022-04-15 0 312
目录
  • 前言
  • 虚拟DOM
    • 什么是虚拟DOM
    • 虚拟DOM的优点
  • 渲染函数是什么
    • jsx
      • 在vue3中编写jsx的两种方式
      • 用法
    • 最后
      • 参考

        前言

        又到了愉快的摸鱼时间,我觉得不能荒废,H5页面我一直用的vant,出于对源码的好奇,我从git上拉了一份vant源码,里面竟然都是jsx写的组件,于是我开始了对在vue中使用jsx的探索

        虚拟DOM

        什么是虚拟DOM

        在这之前,先了解下虚拟DOM,vue和react框架都在内部使用了虚拟DOM,这样做的原因是通过js操作DOM的计算成本很高,虽然js更新速度很快,但是查找dom并更新的成本很高。那么有什么方法可以优化呢,vue等框架使用js对象,通过改变js对象,最后进行批量处理,一次更新DOM,所以虚拟DOM本质上就是一个js对象

        虚拟DOM的优点

        • 从原先的操作真实DOM到操作虚拟DOM,降低查找成本
        • 通过diff比对,我们可以更快的定位数据的变化,从而更新DOM
        • 更好的ui更新
        • 抽象渲染过程,带来了实现跨平台的能力,如vue3中的createRenderer API

        渲染函数是什么

        渲染函数是用来生成虚拟DOM的。我们在vue单文件中编写模板语法,最终会在底层实现中被编译成渲染函数

        Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。

        当出现以下场景,虽然下列写法也能实现想要的效果,但是他不仅冗长,而且我们为每个级别标题重复书写了 。当我们添加锚元素时,我们必须在每个 v-if/v-else-if 分支中再次重复它

        const { createApp } = Vue
        
        const app = createApp({})
        
        app.component('anchored-heading', {
          template: `
            <h1 v-if="level === 1">
              <slot></slot>
            </h1>
            <h2 v-else-if="level === 2">
              <slot></slot>
            </h2>
            <h3 v-else-if="level === 3">
              <slot></slot>
            </h3>
            <h4 v-else-if="level === 4">
              <slot></slot>
            </h4>
            <h5 v-else-if="level === 5">
              <slot></slot>
            </h5>
            <h6 v-else-if="level === 6">
              <slot></slot>
            </h6>
          `,
          props: {
            level: {
              type: Number,
              required: true
            }
          }
        })
        

        虽然模板在大多数组件中都非常好用,但是显然在这里它就不合适了。那么,我们来尝试使用 render 函数重写上面的例子:

        const { createApp, h } = Vue
        
        const app = createApp({})
        
        app.component('anchored-heading', {
          render() {
            return h(
              'h' + this.level, // tag name
              {}, // props/attributes
              this.$slots.default() // array of children
            )
          },
          props: {
            level: {
              type: Number,
              required: true
            }
          }
        })
        

        jsx

        这样写渲染函数有点痛苦,有没有更接近模板的写法呢,vue提供了一个babel-plugin-jsx babel插件来让vue支持jsx写法

        我这边使用的vuecli创建的vue3 + ts项目,脚手架已经集成了jsx和ts的相关依赖

        在vue3中编写jsx的两种方式

        直接将文件后缀名从vue改成tsx或者jsx

        在vue3中,可以直接使用render选项编写

        import { defineComponent } from "vue";
        export default defineComponent({
          name: "Jsx",
          render() {
            return <div>我是一个div</div>;
          },
        });
        
        

        也可以在setup中返回

        import { defineComponent } from "vue";
        export default defineComponent({
          name: "Jsx",
          setup() {
            return () => <div>我是div</div>;
          },
        });
        
        

        两种方式都可以,具体看个人习惯,setup中访问不到this,但是render中可以通过this访问当前vue实例

        用法

        class绑定,和react的jsx绑定的有区别,react中使用className,vue中使用class

         setup() {
           return () => <div class="test">我是div</div>;
         },
        

        style绑定

          setup() {
            return () => <div style={{ color: "red" }}>我是div</div>;
          },
        

        props绑定

        // 父组件
        setup() {
            return () => (
              <div style={{ color: "red" }}>
                <span>我是父组件</span>
                <Mycom msg={"我是父组件传的值"} />
              </div>
         );
        
        // 子组件,setup的第一个参数,可以获取props里的值
          setup(props) {
            return () => <div>我是子组件{props.msg}</div>;
          },
        

        事件绑定

        setup() {
            function eventClick() {
              console.log("点击");
            }
            return () => <button onClick={eventClick}>按钮</button>;
        },
        

        组件自定义事件

        // 子组件
        import { defineComponent } from "vue";
        export default defineComponent({
          name: "Mycom",
          emits: ["event"],
          setup(props, { emit }) {
            function sendData() {
              emit("event", "子组件传递的数据");
            }
            return () => (
              <div>
                <span>自定义事件</span>
                <button onClick={sendData}>传递数据</button>
              </div>
            );
          },
        });
        
        // 父组件
        // @ts-nocheck
        // 这样写在jsx中没问题,但是在tsx中会报ts类型错误,所以我在上面忽略了当前文件ts监测@ts-nocheck
        import { defineComponent } from "vue";
        import Mycom from "./mycom";
        export default defineComponent({
          name: "Jsx",
          setup() {
            function getSon(msg: string) {
              console.log(msg);
            }
            return () => (
              <div>
                <Mycom onEvent={getSon} />
              </div>
            );
          },
        });
        
        

        也可以这样解决ts类型报错

          setup() {
            function getSon(msg: string) {
              console.log(msg);
            }
            return () => (
              <div>
                <Mycom {...{ onEvent: getSon }} />
              </div>
            );
          },
        

        插槽

        // 父组件
        setup() {
            const slots = {
              test: () => <div>具名插槽</div>,
              default: () => <div>默认插槽</div>,
            };
            return () => (
              <div>
                <Mycom v-slots={slots}></Mycom>
              </div>
            );
        },
        
        setup(props, { slots }) {
        // 子组件
            return () => (
              <div>
                <span>插槽</span>
                {slots.default?.()}
                {slots.test?.()}
              </div>
            );
          },
        

        指令,v-if,v-for等指令在jsx中无法使用,jsx只支持v-model和v-show指令

          setup() {
            const inputData = ref("");
            return () => (
              <div>
                <span v-show={true}>显示</span>
                <span v-show={false}>隐藏</span>
                <input type="text" v-model={inputData.value} />
                <span>{inputData.value}</span>
              </div>
            );
        },
        

        最后

        话不多说,我先打开vant源码,准备开启我的第一个组件源码阅读 src =>button=>button.tsx

        到此这篇关于vue中正确使用jsx的文章就介绍到这了,更多相关vue中使用jsx内容请搜索NICE源码以前的文章或继续浏览下面的相关文章希望大家以后多多支持NICE源码!

        参考

          vue渲染函数

        • vuejsx文档
        • issues

        免责声明:
        1、本网站所有发布的源码、软件和资料均为收集各大资源网站整理而来;仅限用于学习和研究目的,您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。 不得使用于非法商业用途,不得违反国家法律。否则后果自负!

        2、本站信息来自网络,版权争议与本站无关。一切关于该资源商业行为与www.niceym.com无关。
        如果您喜欢该程序,请支持正版源码、软件,购买注册,得到更好的正版服务。
        如有侵犯你版权的,请邮件与我们联系处理(邮箱:skknet@qq.com),本站将立即改正。

        NICE源码网 JavaScript vue中正确使用jsx语法的姿势分享 https://www.niceym.com/29929.html