乐趣区

关于vue.js:如何在Vue项目中使用JSX

Author:ManStruggling

什么是 JSX?


JSX 是一种 JavaScript 和 XML 的联合,即 JavaScript + XML = JSX,JSX 源于 Facebook,能够在 JavaScript 里写 XML,因为这个个性,所以具备了 JavaScript 的灵活性,同时又兼具 html 的语义化和直观性

为什么应用 JSX?


  • jsx 比照 createElement 函数可读性更强;<div></div> VS this.$createElement(‘div’, {…}, […])
  • vue-cli3.0 及以上默认反对 jsx 语法
  • jsx 能够使 vue 组件更容易导入和治理

首先来横向比照一下 <template></template> 模板语法、createElement 函数、jsx 三种渲染形式

栗子一

template 模板语法

应用最多,不做解释

<div id="vnode">
    一些文本
    <p class="bar" style="color: red; font-weight: bold;">Only you can stop forest fires</p>
    <span>span text</span>
    <b>b tag</b>
</div>
createElement

createElement 函数实际上创立的是 Virtual Node,创立 VNode 树,一旦 Dom 树的结构复杂,dom 节点属性太多,势必会造成可读性差的问题。。。

render(h) {
    return h(
      "div",
      {
        attrs: {id: "vnode",},
      },
      [
        "一些文本",
        h(
          "p",
          {
            class: {bar: true,},
            style: {
              color: "red",
              fontWeight: "bold",
            },
          },
          "Only you can stop forest fires"
        ),
        h("span", {}, "span text"),
        h("b", { domProps: { innerText: "b tag"} }),
      ]
    );
  }
JSX

而后 jsx 就闪亮退场

render() {
    return (
      <div id="vnode">
        一些文本
        <p class="bar" style="color: red; font-weight: bold;">
          Only you can stop forest fires
        </p>
        <span>span text</span>
        <b>b tag</b>
      </div>
    );
  }

可能有的同学感觉,就这,跟 template 没什么区别呀。

这个案例只波及到 html 没有波及 javascript,jsx 是把 javascript 和 html 放在一起来书写的。所以看下个栗子

栗子二

依据 type 的值进行条件渲染,A、B、C 三个模块,每个模块有本人的对应模块的代码,也有一些公共的模块,假如这些代码有很多行,势必会造成浏览性的升高。有人可能感觉如果这样的话,把公共代码抽离出一个独自的组件不就好了,这样使能够解决问题,如果这里的公共代码仅仅只在这一个文件内应用,别的文件不会对这些公共代码做援用呢,要不要思考抽离公共组件的必要性呢,jsx 就能够完满的解决这些问题。

template

,在 template

<div>
        <!-- 模块 A -->
        <div class="module-a" v-if="type === 0">
            <div>
                ... 模块 A 的代码
            </div>
            <div>
                ... 公共代码
            </div>
        </div>
        <!-- 模块 B -->
        <div class="module-b" v-else-if="type === 1">
            <div>
                ... 模块 B 的代码
            </div>
            <div>
                ... 公共代码
            </div>
        </div>
        <!-- 模块 C -->
        <div class="module-c" v-else>
            <div>
                ... 模块 C 的代码
            </div>
            <div>
                ... 公共代码
            </div>
        </div>
    </div>
createElement

这里就不做 createElement 函数的阐明了,想必也没有多少人用这个吧。。。。有的话,那你赢了

JSX

template 模板代码超过三百行,就很难浏览了,会反复在 VM、V 层切换,所以在简单的大型项目中倡议用 jsx 来做 render,进步代码的可浏览性

render() {
    // 提取公共模块代码
    const renderCommon = () => <div>... 公共代码 </div>;
    const renderA = () => (
      <div class="module-a">
        <div>... 模块 A 的代码 </div>
        {renderCommon()}
      </div>
    );
    const renderB = () => (
      <div class="module-b">
        <div>... 模块 B 的代码 </div>
        {renderCommon()}
      </div>
    );
    const renderC = () => (
      <div class="module-c">
        <div>... 模块 C 的代码 </div>
        {renderCommon()}
      </div>
    );
    return (
      <div>
        {this.type === 0 ? renderA() : this.type === 1 ? renderB() : renderC()}
      </div>
    );
  }

Usage


<script>
export default {render() {
    // 条件渲染
    const vIfRender = () => {
      let show = false;
      return (
        <div
          id={"test"}
          class={{"test-wrapper": true}}
          style={{fontWeight: "bold"}}
        >
          {show ? <div>display</div> : "hidden"}
        </div>
      );
    };
    // v-html 渲染
    const vHtmlRender = () => <div domPropsInnerHTML={`<i>i text</i>`}></div>;
    const listRencer = () => (
      <ol>
        {[1, 2, 3, 4, 5].map((item) => (<li>{item}</li>
        ))}
      </ol>
    );
    // 事件绑定
    const handleParentClick = () => {console.log("trigger parent click");
    };
    const handleClick = (e) => {e.stopPropagation();
      console.log("trigger click");
    };
    const eventBindingRender = () => (<div onClick={handleParentClick}>
        parent text
        <button domPropsInnerHTML={"点一下试试"} onClick={handleClick}></button>
      </div>
    );
    // 属性绑定
    const inputAttrs = {
      type: "number",
      placeholder: "请输出数字",
    };
    const attrBindingRender = () => <input {...{ attrs: inputAttrs}} />;
    // 指令
    const directiveBindingRender = () => (
      <button
        {...{
          directives: [
            {
              name: "permission",
              value: 666,
              modifiers: {foo: true},
            },
          ],
        }}
      >
        权限治理
      </button>
    );
    return (
      <div>
        {
          // v-if 三目运算符
          vIfRender()}
        {
          // v-html
          vHtmlRender()}
        {
          // 列表渲染
          listRencer()}
        {
          // 事件绑定
          eventBindingRender()}
        {
          // 属性绑定
          attrBindingRender()}
        {
          // 指令
          directiveBindingRender()}
      </div>
    );
  },
};
</script>

插槽和作用域插槽

// child.vue
<script>
export default {
    props: {
        config: {
            type: Object,
            required: true
        }
    },
    render() {
        return (
            <div>
                <h3>{this.config.text}</h3>
                {this.$scopedSlots.content({data: this.config.childConfig})}
            </div>
        )
    }
}
</script>
<script>
import Child from "./child";
export default {render() {
    const config = {
      text: "parent text jsx",
      childConfig: {test: "children text jsx",},
    };
    return (
      <div>
        <Child
          config={config}
          {...{
            scopedSlots: {content: ({data}) => {return <div>{data.test}</div>;
              },
            },
          }}
        ></Child>
      </div>
    );
  },
};
</script>

组件间接引入应用,无需 components 注册,不便导入和治理


上述总结应用 jsx 的一些非凡状况,条件渲染、v-html、列表的渲染、事件的绑定、属性绑定、指令的应用、插槽和作用域插槽,聪慧的你必定能够看进去,应用 jsx 能像 vue3 的 composition API 一样把雷同的逻辑代码聚合在一起,防止大型项目开发时,页面逻辑简单导致代码量回升,option API 在 template 和 methods 之间来回切换的问题。

第一次撰文,如有疑难,欢送各位大佬斧正,心愿大家可能 STAR 反对一下小编,心愿小编的内容对大家有所帮忙~

[TOC]

退出移动版