您当前的位置:首页 > 网站建设 > javascript
| php | asp | css | H5 | javascript | Mysql | Dreamweaver | Delphi | 网站维护 | 帝国cms | React | 考试系统 | ajax |

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

51自学网 2022-05-02 21:36:10
  javascript

前言

又到了愉快的摸鱼时间,我觉得不能荒废,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 } = Vueconst 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 } = Vueconst 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-nocheckimport { 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内容请搜索wanshiok.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持wanshiok.com!

参考


Vue3使用路由VueRouter4的简单示例
React中refs的一些常见用法汇总
51自学网,即我要自学网,自学EXCEL、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。
京ICP备13026421号-1