如何在Vue項目中使用JSX?

2021-12-19 SegmentFault思否

作者:ManStruggling

來源:SegmentFault 思否社區

什麼是 JSX?

JSX是一種JavaScript和XML的結合,即JavaScript + XML = JSX,JSX源於Facebook,可以在JavaScript裡寫XML,因為這個特性,所以具備了JavaScript的靈活性,同時又兼具html的語義化和直觀性

為什麼使用 JSX?首先來橫向對比一下<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>

createElementcreateElement函數實際上創建的是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
<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函數的說明了,想必也沒有多少人用這個吧。。。。有的話,那你贏了JSXtemplate模板代碼超過三百行,就很難閱讀了,會重複在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支持一下小編,希望小編的內容對大家有所幫助~點擊左下角閱讀原文,到 SegmentFault 思否社區 和文章作者展開更多互動和交流,掃描下方」二維碼「或在「公眾號後臺「回復「 入群 」即可加入我們的技術交流群,收穫更多的技術文章~

相關焦點

  • 來聊聊Vue中使用Render函數和JSX
    說白了就是可以在JavaScript代碼中使用JSX。JavaScript在解析JSX時會先創建虛擬DOM,JSX最後會被編譯為JavaScript代碼執行。為什麼要用JSX有的人肯定覺得用render函數寫如果嵌套子級太多層看著太彆扭了,可讀性太差。
  • 用 jsx 寫 vue 組件
    的組件時,一般都是用的是模版,這種方式看起來比較簡潔,而且vue作者也推薦使用這個方式,但是這種方式也有一些它的弊端,例如模版調試麻煩,或者在一些場景下模版描述可能沒那麼簡單和方便。下面我們要講的是如何在vue裡面寫jsx,知道react的人應該都知道jsx,jsx的一個特性就是非常靈活,雖然有的人覺得jsx很醜陋,把邏輯都寫到模版的感覺,但蘿蔔青菜各有所愛,適合自己適合團隊的就是最好的。
  • vue高級進階系列——用typescript玩轉vue和vuex
    說的簡單點就是對vue的狀態進行統一管理,如下圖介紹了其管理模式:最簡單的使用方法長這樣的:// 如果在模塊化構建系統中,請確保在開頭調用了 Vue.use(Vuex)const store = new Vuex.Store({state: {count: 0},mutations: {increment
  • 我是如何在公司項目中使用ESLint來提升代碼質量的
    為什麼我們要在項目中使用ESLintESLint可以校驗我們寫的代碼,給代碼定義一個規範,項目裡的代碼必須按照這個規範寫。加入ESLint有非常多的好處,比如說可以幫助我們避免一些非常低級的錯誤,一些格式上的問題導致我們在運行生產環境的時候出現一些不明所以的報錯。
  • 如何在vue項目中使用sass並設置元素樣式
    elementJavaScriptsassCSS3 在創建vue框架項目時,可以使用CSS3定義元素樣式;還可以使用sass動態變量定義元素樣式如果直接使用sass,啟動項目會出現報錯。那麼,如何在vue項目中使用sass?
  • 前端神器:一行命令,React 組件轉 Vue 組件!
    本文先介紹兩個框架的組件共性和不兼容的地方,再介紹react-to-vue的使用和原理。在實際業務中,陸金所100多個的react基礎業務組件,react-to-vue可以轉化90%以上,變成vue組件。
  • Vue.js 框架作者公布 Vue 3 最新進展
    Vue Router目前存在部分與 vue-router@3.x 相關的路由鉤子 (router hook)行為一致性問題,這也是 Vue Router 沒有被標記為 Beta 的原因。不過在非關鍵項目上可以使用新的路由。
  • 如何在vue框架項目中使用echarts並製作柱狀圖
    cnpm install --global vue-cli2、接著使用命令:vue init webpack wanm,創建一個基於webpack模板的新項目運行項目:npm run dev4、如果要在vue框架項目中使用echarts,需要安裝echartsnpm install echarts
  • 如何在vue項目中使用muse-ui並創建一個form表單提交
    Muse UI是基於vue的開源組件庫,包含了不同的控制項;可以自定義主題,實現定製化。如果在vue項目中,如何使用muse-ui?cnpm install --global vue-cli3、使用vue init命令初始化項目,創建基於webpack模板的項目vue init
  • 如何創建vue項目並使用element框架中的el-select
    cnpm install --global vue-cli2、創建一個基於webpack模板項目,使用命令vue init webpack wmnvue init webpack wmn3、項目安裝完畢,切換路徑,使用命令cd wmn命令:cd wmn
  • 【組件庫從0到1】Vite + Vue3 + TSX開發指南
    實踐中,我們如何刻意提升自己這方面的能力,我覺得給公司搭建一套組件庫就很好。Vite項目中引入JSX。我們可以通過一個叫做@vitejs/plugin-vue-jsx插件實現,首先安裝它:yarn add @vitejs/plugin-vue-jsx -D
  • 在Typescript項目中,如何優雅的使用ESLint和Prettier
    此外由於性能問題,TypeScript 官方決定全面採用ESLint,甚至把倉庫作為測試平臺,而 ESLint 的 TypeScript 解析器也成為獨立項目,專註解決雙方兼容性問題。  最近在我的項目的編碼規範中全量的用ESLint代替了TSLint,針對其中遇到的問題做一個記錄。
  • 實戰教學使用 Vue3 重構 Vue2 項目(萬字好文推薦)
    本文來自於 神奇的程式設計師 的分享好文,點擊閱讀原文查看作者的掘金鍊接。
  • 一個niubility的Vue遊戲,真厲害!(收藏)
    ,以及如何把 React 項目重構為 Vue 版本Vue 版本和 React 版本核心代碼基本相同,但在編寫組件的時候遇到了幾個問題,比如:如何把 React 組件改寫成 Vue 的,我的思路是把組件當成函數,保證一個輸入(props)能得到一個確定的輸出(view),然後對不同方法也是做同樣處理, React 的 setState 會觸發 render 方法,所以可以在 methods
  • 在vue項目中使用vuex實現狀態管理的案例
    說明:其實如果項目不是很龐大很複雜,沒有涉及到很多狀態值需要被很多頁面或組件共用;或者某個頁面或組件的行為會對其他頁面或組件造成依賴性的影響。並不需要使用vuex。vuex的使用與否在實際開發中應該視項目情況而定。
  • 【乾貨】Vue的class語法與常規語法對照表
    項目中使用的是vue-class-component、vue-property-decorator配合TypeScript來進行開發的,其中vue-class-component提供了class語法,而vue-property-decorator提供了一些裝飾器來方便代碼的組織和編寫。
  • vue-i18n 在 JS 文件中如何使用
    項目中,vue-i18n是一個比較流行的多語言方案。常規用法是在項目入口文件裡,將它作為插件引入,然後在 .vue文件或者組件模板裡按照 API 來調用就行。插件會自動往組件實例中注入$t方法。$mount('#app')//App.vue<div id="app">  <p>{{ $t("message.hello") }}</p></div>問題來了,如果不在組件模板裡怎麼辦?比如一些工具函數,請求攔截器等跟視圖無關的JS代碼中如何使用呢?
  • 一文搞定前端自動化測試(Vue 實戰)
    前面兩篇還沒學習過的同學,建議先學習前面的內容再來看這一篇文章:本文中所有代碼都存放在此倉庫:Learning-Vue-Test[3]本文中實現的 Button 組件在此處可以預覽:Learning-Vue-Test[4]創建項目首先需要創建一個項目來開始我們的自動化測試實戰
  • 如何在uni-app項目中使用vue計算屬性
    工具HBuilderX微信開發者工具技術vueuni-appJavaScriptuni-app是 Vue.js 開發所有前端應用的框架,因此可以使用vue中的相關屬性,如計算屬性computed。其中,computed計算屬性是控制表達式結果的。
  • 面試官:說說如何在Vue項目中應用TypeScript?
    一、前言與如何在React項目中應用TypeScript類似在VUE項目中應用typescript,我們需要引入一個庫vue-property-decorator,其是基於vue-class-component庫而來,