詳解Vue3+Vite中怎麼使用JSX

2022-12-09 22:00:40
+Vite中怎麼使用JSX?下面本篇文章給大家介紹一下Vue3+Vite 中 JSX 的使用方式,希望對大家有所幫助!

前端(vue)入門到精通課程,老師線上輔導:聯絡老師
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:

【相關推薦:、】

JSX介紹

JSX(JavaScript 和 XML),是一個 HTML-in-JavaScript 的語法擴充套件,首先在 React 中被進入。JSX 可以很好地描述 UI 應該呈現出它應有互動的本質形式。JSX 是在 JavaScript 語法上的拓展,因此類似於 HTML 的程式碼可以和 JS 共存。例如:

const button = <MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>
登入後複製

該 button 常數稱為 JSX 表示式。可以使用它在我們的應用程式中渲染 <MyButton> 標籤。瀏覽器是無法讀取直接解析 JSX 的。JSX 表示式經過( Babel 或 Parcel 之類的工具)編譯之後是這樣的:

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)
登入後複製

實際上,JSX 僅僅只是 React.createElement(component, props, ...children) 函數的語法糖。可以使用 React.createElement() 自己編寫 UI 來跳過編譯步驟。但是,這樣做會失去 JSX 的宣告性優勢,並且程式碼變得更難以閱讀。編譯是開發過程中的一個額外步驟,但是 React 社群中的許多開發人員都認為 JSX 的可讀性值得。另外,流行的工具使 JSX-to-JavaScript 編譯成為其設定過程的一部分。除非您願意,否則不必自己設定編譯。如果你想測試一些特定的 JSX 會轉換成什麼樣的 JavaScript,你可以嘗試使用 。

React 並不強制要求使用 JSX。當你不想在構建環境中設定有關 JSX 編譯時,不在 React 中使用 JSX 會更加方便。例如,用 JSX 編寫的程式碼:

class Hello extends React.Component {
  render() {
    return <div>Hello {this.props.toWhat}</div>;
  }
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Hello toWhat="World" />);
登入後複製

可以編寫為不使用 JSX 的程式碼:

class Hello extends React.Component {
  render() {
    return React.createElement('div', null, `Hello ${this.props.toWhat}`);
  }
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(Hello, {toWhat: 'World'}, null));
登入後複製

在 Vue3 中使用 JSX

Vue 使用單檔案元件,把 template 模板、相關指令碼和 CSS 一起整合放在 .vue 結尾的一個單檔案中。這些檔案最終會通過 JS 打包或構建工具(例如 Webpack、Vite)處理。

<template> 元素包含了所有的標記結構和元件的展示邏輯。template 可以包含任何合法的 HTML,以及 Vue 特定的語法。通過設定 <template> 標籤的 lang 屬性,例如可以通過設定 <template lang="pug"> 就可以在使用 Pug 模板來替代標準 HTML。

而 .vue 檔案中的 <script> 標籤包含元件中所有的非顯示邏輯,並且需要預設匯出一個 JS 物件。該物件是在本地註冊元件、定義屬性、處理本地狀態、定義方法等的地方。在構建階段這個包含了 template 模板的物件會被處理和轉換成為一個有 render() 函數的 Vue 元件。

元件的 CSS 樣式寫在 <style> 標籤裡,如果新增了 scoped 屬性,Vue 會把樣式的範圍限制到單檔案元件的內容裡。這是類似於 CSS-in-JS 的解決方案,只不過允許書寫純粹的 CSS。如果通過 CLI 建立專案時選擇了 CSS 前處理器,則可以將 lang 屬性新增到 <style> 標籤中,以便 Webpack 可以在構建時處理內容。

雖然 jsx 最早是由 React 引入,但實際上 JSX 語法並沒有定義執行時語意,並且能被編譯成各種不同的輸出形式。如果你之前使用過 JSX 語法,那麼請注意 Vue 的 JSX 編譯方式與 React 中 JSX 的編譯方式不同,因此不能在 Vue 應用中使用 React 的 JSX 編譯。與 React JSX 語法的一些明顯區別包括:

  • 可以使用 HTML attributes 比如 classfor 作為 props - 不需要使用 classNamehtmlFor
  • 傳遞子元素給元件 (比如 slots) 的。

Vue 的型別定義也提供了 TSX 語法的型別推導支援。當使用 TSX 語法時,確保在 tsconfig.json 中設定了 "jsx": "preserve",這樣的 TypeScript 就能保證 Vue JSX 語法編譯過程中的完整性。

安裝外掛(@vitejs/plugin-vue-jsx)

vite 官方提供了官方的外掛來支援在 vue3 中使用 jsx/tsx,直接安裝就行。

npm i @vitejs/plugin-vue-jsx -D
登入後複製

安裝完之後在 vite.config.js 檔案中的 plugins 欄位中新增 jsx 支援:

import vueJsx from "@vitejs/plugin-vue-jsx";

export default defineConfig({
  plugins: [
    vueJsx(),
  ]
})
登入後複製

這樣就可以在專案中使用 jsx/tsx 了。

新建 jsx 檔案

在專案中新建 jsx 或 tsx 字尾的檔案,語法和 js 檔案類似,但是和 .vue 檔案中的 <script> 標籤一樣需要預設匯出一個 JS 物件。該物件是在本地註冊元件、定義屬性、處理本地狀態、定義方法等的地方。

import HelloWorld from './HelloWorld.vue'
export default {
  setup() {
    return () => <HelloWorld msg="11" />;
  },
};
登入後複製

語法

1、插值。與 vue 模板語法中的插值一樣,但是雙大括號 {{}} 變為了單大括號 {}。大括號內支援任何有效的 JavaScript 表示式,比如:2 + 2,user.firstName,formatName(user) 等。

// 模板語法
<span>{{ a + b }}</span>

// jsx/tsx
<span>{ a + b }</span>
登入後複製

2、class 類名系結。有兩種方式,使用模板字串或者使用陣列。

// 模板字串
<div className={ `header ${ isBg ? 'headerBg' : '' }` }>header</div>
// 陣列
<div class={ [ 'header', isBg && 'headerBg' ] } >header</div>
登入後複製

3、style 樣式繫結。需要使用雙大括號。

const color = 'red'
const element = <sapn style={{ color, fontSize: '16px' }}>style</sapn>
登入後複製

4、條件渲染。由於 jsx 本身具有 js 語法,所以不再需要使用 v-if 指令,使用 if/else 和三元表示式都可以實現。但是支援 v-show 指令。

const element = (name) => {
  if (name) {
    return <h1>Hello, { name }</h1>
  } else {
    return <h1>Hello, Stranger</h1>
  }
}

const element = icon ? <span class="icon"></span> : null;
// 以上程式碼等效於:
const element = icon && <span class="icon"></span>;
登入後複製

5、列表渲染。同樣,由於 jsx 本身具有 js 語法,所以不再需要使用 v-for 指令,使用 JS 陣列的 map 方法即可。

const listData = [
   {name: 'Tom', age: 18},
   {name: 'Jim', age: 20},
   {name: 'Lucy', age: 16}
]
return () => (
   <div>
     <div class={'box'}>
       <span>姓名</span>
       <span>年齡</span>
     </div>
   {
   prop.listData.map(item => <div class={'box'}>
       <span>{item.name}</span>
       <span>{item.age}</span>
     </div>
     })
   </div>
)
登入後複製

6、標籤屬性繫結。也是使用大括號包裹,不能使用 v-bind 指令。而 vue 元件中通過 <div v-bind="properties"></div> 批次繫結標籤屬性,在 JSX 中需要使用 <div {...properties}></div>

const href = 'https://cn.vuejs.org/'
const element = <a href={href}>Vue3</a>
登入後複製

7、事件繫結。使用的也是 單大括號 {},不過事件繫結不是以 @為字首了,而是改成了 on,與原生相同。例如:click 事件是 onClick 或 onclick。

const confirm = () => {
  // 確認提交
}
<button onClick={confirm}>確定</button>
登入後複製

如果要帶引數,需要使用箭頭函數進行包裹:

const confirm = (name) => {
  // 確認提交
}
<button onClick={() => confirm('Are you sure')}>確定</button>
登入後複製

8、事件修飾符。需要使用 withModifiers 方法,接收兩個引數,第一個引數是繫結的事件,第二個引數是需要使用的事件修飾符。

import { withModifiers, defineComponent, ref } from 'vue'

const App = defineComponent({
  setup() {
    const count = ref(0);

    const inc = () => {
      count.value++;
    };

    return () => (
      <div onClick={ withModifiers(inc, ['self']) }>{ count.value }</div>
    );
  },
})
export default App
登入後複製

注意:Vue 模板中 ref 變數是可以直接解構的,但是在 jsx 中不行,需要新增 .value,比如上面的 { count.value }。

9、v-model 雙向繫結。需要使用單大括號 {}。如果繫結屬性則需要一個陣列,第一個元素為繫結的值,第二個元素為繫結的屬性。

// 繫結值
<input v-model="show" /> // vue
<input v-model={show.value} /> // jsx

// 繫結屬性
<input v-model:prop="show" /> // vue
<input v-model={[show.value,'prop']} /> // jsx

// 修飾符寫法
<input v-model:prop.trim="show" /> // vue
<input v-model={[show.value,'prop',['trim']]} /> // jsx
登入後複製

10、slot 插槽。jsx/tsx 中無法使用 slot 標籤,定義插槽方式一:通過 setup 函數的第一個引數 ctx 上下文物件的 slots 的屬性,setup 函數預設接收兩個引數:

  • props - 元件傳入的引數物件。
  • ctx - 上下文物件,上下文物件暴露了其他一些在 setup 中可能會用到的值,包括:
    • attrs - 透傳的 Attributes(非響應式的物件,等價於 $attrs)。
    • slots - 插槽(非響應式的物件,等價於 $slots)。
    • emit - 觸發事件的函數(等價於 $emit)。
    • expose - 暴露公共屬性的函數。

如果解構了 props 物件,解構出的變數將會丟失響應性,因此推薦通過 props.xxx 的形式來使用其中的 props。如果確實需要解構 props 物件,或者需要將某個 prop 傳到一個外部函數中並保持響應性,可以使用 和 這兩個工具函數:

import { toRefs, toRef } from 'vue'

export default {
  setup(props) {
    // 將 `props` 轉為一個其中全是 ref 的物件,然後解構
    const { title } = toRefs(props)
    // `title` 是一個追蹤著 `props.title` 的 ref
    console.log(title.value)

    // 或者,將 `props` 的單個屬性轉為一個 ref
    const title = toRef(props, 'title')
  }
}
登入後複製

ctx 上下文物件是非響應式的,可以安全地解構:

export default {
  setup(props, { attrs, slots, emit, expose }) {
    ...
  }
}
登入後複製

attrs 和 slots 都是響應式(有狀態)的物件,它們總是會隨著元件自身的更新而更新。這意味著你應當避免解構它們,並始終通過 attrs.x 或 slots.x 的形式使用其中的屬性。此外,和 props 不同,attrs 和 slots 的屬性都不是響應式的。如果想要基於 attrs 或 slots 的改變來執行副作用,那麼應該在 onBeforeUpdate 生命週期勾點中編寫相關邏輯。

expose 函數用於顯式地限制該元件暴露出的屬性,當父元件通過模板參照存取該元件的範例時,將僅能存取 expose 函數暴露出的內容:

export default {
  setup(props, { expose }) {
    // 讓元件範例處於 「關閉狀態」
    // 即不向父元件暴露任何東西
    expose()

    const publicCount = ref(0)
    const privateCount = ref(0)
    // 有選擇地暴露區域性狀態
    expose({ count: publicCount })
  }
}
登入後複製

通過 ctx 上下文物件的 slots 的屬性可以獲取插槽物件後,就可以定義插槽了。

import { defineComponent } from 'vue'

export default defineComponent({
  setup(props, { slots }) { // 邏輯
    return () => {
      return <p>
     <button>{ slots.test?.() }</button>
     <button>{ slots.default?.() }</button>
     </p>
    }
  },
})

// 在參照的元件中
<template #test>slot-test</template>
<template #>slot-default</template>
登入後複製

定義插槽方式二:使用 renderSlot 函數。

import { renderSlot } from 'vue'

<button>
  { renderSlot(slots, 'default') }
</button>
登入後複製

而如果在 jsx 中使用插槽,可以直接通過標籤屬性 slot,或通過 v-slots 指令。

import HelloWorld from './HelloWorld'  
export default defineComponent({  
    setup() {  
        return () => (  
            <div class={'box'}>  
                <HelloWorld v-slots={{  
                    title: () => {  
                        return <p>我是title插槽</p>  
                    },  
                    default: () => {  
                        return <p>我是default插槽</p>  
                    }  
                }} />  
            </div>  
        )  
    }  
})
登入後複製

11、CSS Modules。引入區域性樣式,相當於 vue 元件中 <style> 標籤的 scoped 屬性。

import styles from './index.module.scss'

<div class={styles.wrap}></div>
登入後複製

GitHub 原始碼

(學習視訊分享:、)

以上就是詳解Vue3+Vite中怎麼使用JSX的詳細內容,更多請關注TW511.COM其它相關文章!