如何在 Vue 中使用 JSX 以及使用它的原因

前端小智發表於2020-02-10

作者:JT

譯者:前端小智

來源:scotch.io/

點贊再看,養成習慣

本文 GitHub github.com/qq449245884… 上已經收錄,更多往期高贊文章的分類,也整理了很多我的文件,和教程資料。歡迎Star和完善,大家面試可以參照考點複習,希望我們一起有點東西。

Vue.js 具有簡單的 API 和幾個選項,可用於在我們的元件中定義HTML模板。

我們可以使用<template>標籤選項,在根元件例項上定義template屬性,或者使用單檔案元件。

上面的選項很棒並且可以完美地工作,但是,在您的應用程式的生命週期中,有時會感到笨拙,設計過度或非常不靈活。

那麼,我們為什麼要使用 JSX 而不是其他模板定義呢?

  • JSX 更易讀,<div></div> 的寫法一看就是比 this.$createElement('div', {}, [...]) 簡潔很多。
  • JSX 也是 JavaScript。
  • Vue支援JSX。
  • JSX 使自定義 Vue 元件更容易匯入和管理。

簡介

先舉一個例子來說明為什麼 JSX 是好的。

我們要構建一個<TextField/>元件,該元件可以是普通的單行文字輸入或多行輸入(文字區域)。 我們的模板宣告可能看起來像這樣。

 <div>
   <textarea v-if="multiline" v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false">
   <input v-else v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false">
 </div>
複製程式碼

從上面的程式碼片段中可以看到,我們很快就會遇到一些問題,比如重複程式碼等等。想象一下,必須支援input上面所列的各種屬性。上面的這個小片段將會增長併成為一個難以維護的噩夢。

要解決這個問題,我們需要使用Vue進行降級處理,因此需要使用理接近Vue的內部API來解決這個問題。

render() 方法

注意:這裡並不是說沒有JSX就沒有一種簡單的方法來處理上面的問題,只是說將這個邏輯移動到帶有JSX的render()方法可以使元件更直觀。

我們在 Vue 中建立的每個元件都有一個render方法。這個就是 Vue 選擇渲染元件的地方。即使我們不定義這個方法,Vue 也會為我們做這件事。

這意味著當我們在 Vue 中定義 HTML 模板時,Vue 的模板編譯器將其編譯為一個createElement函式,該函式帶有幾個引數並從render函式返回結果。

為了修復上一節中的程式碼,我們刪除了template屬性或template標籤,並在元件上定義了render()方法。 如果在元件上定義了render方法,則 Vue 將忽略template定義。

...
 export default {
     name: 'TextField',
     render (createElement) {
         const tag = this.multiline ? 'textarea' : 'input'

        return createElement(tag, {
             class: {
                 'text-input': true,
                 'is-disabled': false
             },
             attrs: {
                 name: this.name,
                 placeholder: this.placeholder,
                 'aria-invalid': false
             }
         })
     } 
 }
...
複製程式碼

上面的程式碼做了幾件事:

  1. render方法從Vue獲取一個createElement助手。
  2. 我們以程式設計方式定義我們的標籤。
  3. 然後,我們建立標籤並將其屬性,類等作為物件傳遞。 我們可以傳遞給createElement選項很多。
  4. 我們返回新建立的元素進行渲染。

我們為 Vue 元件定義的每個模板都將轉換為可返回createElement函式的render方法。 因為這個原因,render方法將優先於模板定義。

舉個例子:

// HTML
<div>
  <p>Only you can stop forest fires</p>
</div>
複製程式碼

模板編譯器將把上面的 HTML 轉換成:

...
render (createElement) {
  return createElement(
    'div',
    {},
    createElement(
      'p',
      {},
      'Only you can stop forest fires'
    )
  )
}
...
複製程式碼

現在你可能會問這個問題:“對可讀性來說這不好嗎?” 答案是肯定的。 一旦定義了具有許多元素巢狀級別或具有多個同級元素的元件,我們就會遇到這個新問題。

這就是 JSX 出現的原因,它可以很好的解決此類問題。

JSX 是什麼

JSX 是 Facebook 工程團隊創造的一個術語。

JSX 是 JavaScript 的類似XML的語法擴充套件,沒有任何定義的語義。

JSX 不打算由引擎或瀏覽器實現。相反,我們將使用 Babel 之類的轉置器將JSX轉換成常規的 JS 。

// 此行是JSX的示例
const heading = <h1>Welcome to Scotch</h1>;
複製程式碼

基本上,JSX 允許我們在 JS 中使用類似 Html 的語法。

配置 Vue 以使用 JSX

如果使用的 Vue-cli 大於或等於 3.0 版本,那麼就直接可以使用JSX的語法了。

如果您使用的是不支援 JSX 的Vue-cli較舊版本,則可以通過安裝babel-preset-vue-app來新增它,並將其新增到您的.babelrc檔案中。

 # Using npm
 npm install --save-dev babel-preset-vue-app

# Using yarn
 yarn add --dev babel-preset-vue-app
複製程式碼

.babelrc檔案中,新增:

{
 "presets": ["vue-app"]
}
複製程式碼

我們現在可以在元件的render函式中使用 JSX。

在 Vue 中使用 JSX 需要注意的地方

在 Vue 中使用JSX需要注意幾點。

要監聽 JSX 中的事件,我們需要“on”字首。 例如,將onClick用於單擊事件。

 render (createElement) {
     return (
         <button onClick={this.handleClick}></button>
     )
 }
複製程式碼

要修改事件,請使用

 render (createElement) {
     return (
         <button onClick:prevent={this.handleClick}></button>
     )
 }
複製程式碼

繫結變數,注意這裡不是使用 :

 render (createElement) {
     return (
         <button content={this.generatedText}></button>
     )
 }
複製程式碼

將HTML字串設定為元素的內容,使用domPropsInnerHTML而不是使用v-html

 render (createElement) {
     return (
         <button domPropsInnerHTML={htmlContent}></button>
     )
 }
複製程式碼

我們也可以展開一個大物件:

 render (createElement) {
     return (
         <button {...this.largeProps}></button>
     )
 }
複製程式碼

在 render 中使用JSX

回到我們最初的“TextField”元件。現在我們已經在 Vue 應用程式中啟用了 JSX,我們現在可以這樣做了。

 render (createElement) {
     const inputAttributes = {
         class: 'input-field has-outline', // class definition
         onClick: this.handleClick // event handler
         backdrop: false // custom prop
     }
     const inputMarkup = this.multiline
         ? <textarea {...inputAttributes}></textarea>
         : <input {...inputAttributes}/>


    return inputMarkup
 }
複製程式碼

匯入 Vue JS 元件

在 Vue 中使用JSX的另一個好處是,我們不再需要註冊所需的每個元件。 我們只是匯入和使用。

import {Button} from '../components'

export default {
     render (createElement) {
         return <Button primary={true}>Edit</Button>
     }
 }
複製程式碼

如何使 JSX 與 TypeScript 一起使用

TypeScript 用作一種向 JavaScript新增型別檢查的機制。要在 JSX 支援 TypeScript中,需要修改 tsconfig.json

要在 TypeScript 中啟用 JSX,請先將該檔案另存為.tsx檔案,然後將tsconfig.json修改為包括:

 {
   "compilerOptions": {
     ....
     "jsx": "preserve",
   }
 }
複製程式碼

jsx選項設定為“preserve”意味著 TypeScript 不應處理JSX。 這樣做使 Babel 可以控制所有JSX 和 TypeScript 堅持使用型別,因為它尚不支援 Vue JSX。

然後在專案中建立一個jsx.d.ts檔案,併為 Vue 新增 TypeScript JSX 宣告。

import Vue, {VNode} from 'vue'

declare global {
   namespace JSX {
     interface Element extends VNode {}
     interface ElementClass extends Vue {}
     interface ElementAttributesProperty {
       $props: {}
     }
     interface IntrinsicElements {
 [elemName: string]: any
     }
   }
 }
複製程式碼

確保 TypeScript 可以載入宣告檔案。 或者,可以通過以下方式在tsconfig.json中為其新增自動載入功能:

 {
   "compilerOptions": {
     ...
     "typesRoot": ["./node_modules/@types", "./types"]
   }
 }
複製程式碼

程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

原文:scotch.io/tutorials/u…


交流

文章每週持續更新,可以微信搜尋「 大遷世界 」第一時間閱讀和催更(比部落格早一到兩篇喲),本文 GitHub github.com/qq449245884… 已經收錄,整理了很多我的文件,歡迎Star和完善,大家面試可以參照考點複習,另外關注公眾號,後臺回覆福利,即可看到福利,你懂的。

如何在 Vue 中使用 JSX 以及使用它的原因

相關文章