中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue中的JSX如何使用

發布時間:2023-01-31 17:50:21 來源:億速云 閱讀:275 作者:iii 欄目:編程語言

今天小編給大家分享一下Vue中的JSX如何使用的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

JSX簡介

JSX是一種Javascript的語法擴展,即具備了Javascript的全部功能,同時又兼具html的語義化和直觀性。它可以讓我們在JS中寫模板語法:

const el = <div>Vue 2</div>;

上面這段代碼既不是 HTML 也不是字符串,被稱之為 JSX,是 JavaScript 的擴展語法。JSX 可能會使人聯想到模板語法,但是它具備 Javascript 的完全編程能力。

什么時候使用JSX

當開始寫一個只能通過 level prop 動態生成標題 (heading) 的組件時,你可能很快想到這樣實現:

<script type="text/x-template" id="anchored-heading-template">
<h2 v-if="level === 1"> 
    <slot></slot> 
</h2> 
<h3 v-else-if="level === 2"> 
    <slot></slot> 
</h3> 
<h4 v-else-if="level === 3"> 
    <slot></slot> 
</h4> 
</script>

這里用template模板并不是最好的選擇,在每一個級別的標題中重復書寫了部分代碼,不夠簡潔優雅。如果嘗試用 JSX 來寫,代碼就會變得簡單很多:

const App = {
  render() {
    const tag = `h${this.level}`
    return <tag>{this.$slots.default}</tag>
  }
}

或者如果你寫了很多 render 函數,可能會覺得下面這樣的代碼寫起來很痛苦:

createElement(  
    'anchored-heading', {  
        props: {  
            level: 1  
        }  
    }, [  
    createElement('span', 'Hello'),  
        ' world!'  
    ]  
)

特別是對應的模板如此簡單的情況下:

<anchored-heading :level="1">  
    <span>Hello</span> world!  
</anchored-heading>

這時候就可以在 Vue 中使用 JSX 語法,它可以讓我們回到更接近于模板的語法上:

import AnchoredHeading from './AnchoredHeading.vue'  
  
new Vue({  
    el: '#demo',  
    render: function (h) {  
        return (  
            <AnchoredHeading level={1}>  
                <span>Hello</span> world!  
            </AnchoredHeading>  
        )  
    }  
})

在開發過程中,經常會用到消息提示組件Message,可能的一種寫法是這樣的:

Message.alert({
  messge: '確定要刪除?',
  type: 'warning'
})

但是希望message可以自定義一些樣式,這時候你可能就需要讓Message.alert支持JSX了(當然也可以使用插槽/html等方式解決)

Message.alert({
  messge: <div>確定要刪除<span style="color:red">xxx</span>的筆記?</div>,
  type: 'warning'
})

此外,一個 .vue 文件里面只能寫一個組件,這個在一些場景下可能不太方便,很多時候寫一個頁面的時候其實可能會需要把一些小的節點片段拆分到小組件里面進行復用,這些小組件其實寫個簡單的函數組件就能搞定了。平時可能會由于SFC的限制讓我們習慣于全部寫在一個文件里,但不得不說可以嘗試一下這種方式。

// 一個文件寫多個組件
const Input = (props) => <input {...props} />
export const Textarea = (props) => <input {...props} />
export const Password = (props) => <input type="password" {...props} />

export default Input

比如這里封裝了一個 Input 組件,我們希望同時導出 Password 組件和 Textarea 組件來方便用戶根據實際需求使用,而這兩個組件本身內部就是用的 Input 組件,只是定制了一些 props。在 JSX 里面就很方便,寫個簡單的函數組件基本上就夠用了,通過 interface 來聲明 props 就好了。但是如果是用模板來寫,可能就要給拆成三個文件,或許還要再加一個 index.js 的入口文件來導出三個組件。

由于 JSX 的本質就是 JavaScript,所以它具有 JavaScript 的完全編程能力。再舉個例子,我們需要通過一段邏輯來對一組 DOM 節點做一次 reverse,如果在模板里面寫,那估計要寫兩段代碼。

雖然這個例子可能不太常見,但是不得不承認,在一些場景下,JSX 還是要比模板寫起來更加順手。

從 Vue 2 開始,template 在運行之前,會被編譯成 JavaScript 的 render function

Vue中的JSX如何使用

Vue 推薦在絕大多數情況下使用 template 來創建你的 HTML。然而在一些場景中,就需要使用 render 函數,它比 template 更加靈活。這些 render function 在運行時階段,就是傳說中的 Virtual DOM

Vue中的JSX如何使用

JSX在Vue2中的基本使用

配置

在 Vue 2 中,JSX 的編譯需要依賴 @vue/babel-preset-jsx@vue/babel-helper-vue-jsx-merge-props 這兩個包。前面這個包來負責編譯 JSX 的語法,后面的包用來引入運行時的 mergeProps 函數。

npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props

并在babel.config.js中添加配置:

module.exports = {
  presets: ['@vue/babel-preset-jsx'],
}

文本插值

模板代碼里文本插值默認是用雙大括號:

<h2>{{ msg }}</h2>

在JSX中則需要使用單大括號:

const name = 'Vue'
const element = <h2>Hello, { name }</h2>

和模板語法中的文本插值一樣,大括號內支持任何有效的JS表達式,比如:2 + 2user.firstNameformatName(user)等。

條件與循環渲染

在模板代碼里面我們通過v-for去遍歷元素,通過v-if去判斷是否渲染元素,在JSX中,對于v-for,可以使用for循環或者array.map來代替,對于v-if,可以使用if-else語句,三元表達式等來代替

使用if-else語句

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

使用三元表達式

const element = icon ? <span class="icon"></span> : null;

使用數組的map方法

const list = ['java', 'c++', 'javascript', 'c#', 'php']
return (
  <ul>
  {list.map(item => {
   return <li>{item}</li>
  })}
  </ul>
)

屬性綁定

在模板代碼中,一般通過 v-bind:prop="value":prop="value"來給組件綁定屬性,在JSX里面就不能繼續使用v-bind指令了,而是通過單大括號的形式進行綁定:

const href = 'https://xxx.com'
const element = <a href={href}>xxx</a>
const properties = {a: 1, b: 2}

此外,模板代碼中能通過<div v-bind="properties"></div>批量綁定標簽屬性。

在JSX中也有相應的替換方案:<div {...properties}></div>

class綁定同樣也是使用單大括號的形式

const element = <div className={`accordion-item-title ${ disabled ? 'disabled' : '' }`}></div>
const element = <div class={
    [ 'accordion-item-title', disabled && 'disabled' ]
  }
>Item</div>

style綁定需要使用雙大括號

const width = '100px'
const element = <button style={{ width, fontSize: '16px' }}></button>

事件綁定

在模板代碼中通過v-on指令監聽事件,在JSX中通過on + 事件名稱的大駝峰寫法來監聽,且綁定事件也是用大括號,比如click事件要寫成onClick,mouseenter事件要寫成onMouseenter

const confirm = () => {
  // 確認提交
}
<button onClick={confirm}>確定</button>

有時候我們希望可以監聽一個組件根元素上面的原生事件,這時候會用到.native修飾符,但是在JSX中同樣也不能使用,不過也有替代方案,監聽原生事件的規則與普通事件是一樣的,只需要將前面的on替換為nativeOn,如下

 render() {
    // 監聽下拉框根元素的click事件
    return <CustomSelect nativeOnClick={this.handleClick}></CustomSelect>
  }

除了上面的監聽事件的方式之外,我們還可以使用對象的方式去監聽事件

  render() {
    return (
      <ElInput
        value={this.content}
        on={{
          focus: this.handleFocus,
          input: this.handleInput
        }}
        nativeOn={{
          click: this.handleClick
        }}
      ></ElInput>
    )
  }

對于 .passive.capture.once 這些事件修飾符,Vue 提供了相應的前綴可以用于 on

Vue中的JSX如何使用

例如:

on: {  
    '!click': this.doThisInCapturingMode,  
    '~keyup': this.doThisOnce,  
    '~!mouseover': this.doThisOnceInCapturingMode  
}

對于所有其它的修飾符,私有前綴都不是必須的,因為你可以在事件處理函數中使用事件方法:Vue中的JSX如何使用

v-show與v-model

大多數指令并不能在JSX中使用,對于原生指令,只有v-show是支持的。

v-modelVue提供的一個語法糖,它本質上是由 value屬性(默認) + input事件(默認)組成的,所以,在JSX中,我們便可以回歸本質,通過傳遞value屬性并監聽input事件來手動實現數據的雙向綁定:

export default {
  data() {
    return {
      name: ''
    }
  },
  methods: {
    // 監聽 onInput 事件進行賦值操作
    handleInput(e) {
      this.name = e.target.value
    }
  },
  render() {
    // 傳遞 value 屬性 并監聽 onInput事件
    return <input value={this.name} onInput={this.handleInput}></input>
  }
}

此外,在腳手架vue-cli4中,已經默認集成了對v-model的支持,可以直接使用<input v-model={this.value}>,如果項目比較老,也可以安裝插件babel-plugin-jsx-v-model來進行支持。

同樣的,在JSX中,對于.sync也需要用屬性+事件來實現,如下代碼所示:

export default {
  methods: {
    handleChangeVisible(value) {
      this.visible = value
    }
  },
  render() {
    return (
      <ElDialog
        title="測試.sync"
        visible={this.visible}
        on={{ 'update:visible': this.handleChangeVisible }}
      ></ElDialog>
    )
  }
}

插槽

(1)默認插槽:

使用element-uiDialog時,彈框內容就使用了默認插槽,在JSX中使用默認插槽的用法與普通插槽的用法基本是一致的,如下

 render() {
    return (
      <ElDialog title="彈框標題" visible={this.visible}>
        {/*這里就是默認插槽*/}
        <div>這里是彈框內容</div>
      </ElDialog>
    )
  }

自定義默認插槽:

Vue的實例this上面有一個屬性$slots,這個上面就掛載了一個這個組件內部的所有插槽,使用this.$slots.default就可以將默認插槽加入到組件內部

export default {
  props: {
    visible: {
      type: Boolean,
      default: false
    }
  },
  render() {
    return (
      <div class="custom-dialog" vShow={this.visible}>
        {/**通過this.$slots.default定義默認插槽*/}
        {this.$slots.default}
      </div>
    )
  }
}

(2)具名插槽

有時候我們一個組件需要多個插槽,這時候就需要為每一個插槽起一個名字,比如element-ui的彈框可以定義底部按鈕區的內容,就是用了名字為footer的插槽

 render() {
    return (
      <ElDialog title="彈框標題" visible={this.visible}>
        <div>這里是彈框內容</div>
        {/** 具名插槽 */}
        <template slot="footer">
          <ElButton>確定</ElButton>
          <ElButton>取消</ElButton>
        </template>
      </ElDialog>
    )
  }

自定義具名插槽: 在上節自定義默認插槽時提到了$slots,對于默認插槽使用this.$slots.default,而對于具名插槽,可以使用this.$slots.footer進行自定義

render() {
    return (
      <div class="custom-dialog" vShow={this.visible}>
        {this.$slots.default}
        {/**自定義具名插槽*/}
        <div class="custom-dialog__foolter">{this.$slots.footer}</div>
      </div>
    )
  }

(3)作用域插槽

有時讓插槽內容能夠訪問子組件中才有的數據是很有用的,這時候就需要用到作用域插槽,在JSX中,因為沒有v-slot指令,所以作用域插槽的使用方式就與模板代碼里面的方式有所不同了。比如在element-ui中,我們使用el-table的時候可以自定義表格單元格的內容,這時候就需要用到作用域插槽

data() {
    return {
      data: [
        {
          name: 'xxx'
        }
      ]
    }
  },
  render() {
    return (
      {/**scopedSlots即作用域插槽,default為默認插槽,如果是具名插槽,將default該為對應插槽名稱即可*/}
      <ElTable data={this.data}>
        <ElTableColumn
          label="姓名"
          scopedSlots={{
            default: ({ row }) => {
              return <div style="color:red;">{row.name}</div>
            }
          }}
        ></ElTableColumn>
      </ElTable>
    )
  }

自定義作用域插槽:

使用作用域插槽不同,定義作用域插槽也與模板代碼里面有所不同。加入我們自定義了一個列表項組件,用戶希望可以自定義列表項標題,這時候就需要將列表的數據通過作用域插槽傳出來。

render() {
    const { data } = this
    // 獲取標題作用域插槽
    const titleSlot = this.$scopedSlots.title
    return (
      <div class="item">
        {/** 如果有標題插槽,則使用標題插槽,否則使用默認標題 */}
        {titleSlot ? titleSlot(data) : <span>{data.title}</span>}
      </div>
    )
  }

使用自定義組件

只需要導入進來,不用再在components屬性聲明了,直接寫在jsx中:

import MyComponent from './my-component'

export default {
  render() {
    return <MyComponent>hello</MyComponent>
  },
}

在method里返回JSX

我們可以定義method,然后在method里面返回JSX,然后在render函數里面調用這個方法,不僅如此,JSX還可以直接賦值給變量,比如:

 methods: {
    renderFooter() {
      return (
        <div>
          <ElButton>確定</ElButton>
          <ElButton>取消</ElButton>
        </div>
      )
    }
  },
  render() {
    const buttons = this.renderFooter()
    return (
      <ElDialog visible={this.visible}>
        <div>內容</div>
        <template slot="footer">{buttons}</template>
      </ElDialog>
    )
  }

用JSX實現簡易聊天記錄

假設該消息聊天記錄的消息類型只有三種:文本,圖片,引用。一條消息里面可以包括任意類型的內容,引用類型消息內部可以不斷嵌套引用其他任意類型消息。效果圖大致如下:

Vue中的JSX如何使用

消息數據結構如下:

message: [
      // 每個數組的第一個參數為消息類型:0:文本 1:圖片 2:引用。第二個參數為具體內容
      [
        0,
        '文本'
      ],
      [
        1,
        '圖片鏈接xxx'
      ],
      [
        2,
        [
          [
            0,
            '引用文本文本文本'
          ],
          [
            1,
            '引用圖片鏈接xxx'
          ]
        ]
      ]
    ]

主要有兩個思路:

1、思路一:在render里返回一段用array.map渲染的消息模板,對于三種消息類型,使用if-else進行判斷分別渲染,對于引用類型的消息,可以封裝一個方法進行渲染,方法里面如果還有引用類型消息就繼續遞歸渲染。

methods: {
    // 展示引用消息
    showQuote (msg) {
      return (
        <div class="content-quote">
          <span class="quote-title">引用:</span>
          {msg.map(item => {
            if (item[0] === 0) {
              return <p class="content-text">{item[1]}</p>
            } else if (item[0] === 1) {
              return (
                <el-image
                  class="content-img"
                  src={item[1]}
                  preview-src-list={[item[1]]}>
                </el-image>
              )
            } else {
              return this.showQuote(item[1])
            }
          })}
        </div>
      )
    }
  },
  render (h) {
    return (
      <ul class="chat-record-list">
        {this.recordList.map(item => {
          return (
            <li
              class="chat-record-item"
              key={item.timeStamp}
            >
              <div class="title">
                <span class="person-info">
                  { `${item.sendUserNick}(${item.sendUserNet}) → ${item.receiverNick}(${item.receiverNet})` }
                </span>
                <span class="sendtime">
                  { this.formatTime('YYYY-mm-dd HH:MM:SS', item.timeStamp) }
                </span>
              </div>
              <div class="content">
                {item.message.map(msg => {
                  if (msg[0] === 0) {
                    return <p class="content-text">{msg[1]}</p>
                  } else if (msg[0] === 1) {
                    return (
                      <el-image
                        class="content-img"
                        src={msg[1]}
                        preview-src-list={[msg[1]]}>
                      </el-image>
                    )
                  } else {
                    // 遞歸渲染引用類型消息
                    return this.showQuote(msg[1])
                  }
                })}
              </div>
            </li>
          )
        })}
      </ul>
    )
  }

2、思路二:第一種思路中封裝的showQuote里面的代碼與render中渲染消息內容的代碼基本相似,因此其實現方式不夠優雅。其實可以將整個消息的渲染封裝成一個組件,在該組件內引入自己,然后再渲染自己。由于具體細節代碼與上述類似,這里只給出思路代碼,具體細節請忽略

// 當前組件就是RecordMessage組件,自己引入自己
import RecordMessage from './RecordMessage.vue'

export default {
    props: {
        message: {
            type: Array,
            default: () => []
        }
    },
    render () {
        const parseMessage = msg => {
            const type = msg[0]
            if (type === 0) {
                // 文本
            } else if (type === 2) {
                // 圖片
            } else {
                // 引用類型
                return (
                    <div>
                        <div>引用:</div>
                        {
                            msg[1].map(subMsg => (
                                // 自己遞歸渲染自己
                                <recored-message>
                                </recored-message>
                            ))
                        }
                    </div>
                )
            }
        }
        return parseMessage(this.message)
    }

以上就是“Vue中的JSX如何使用”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

太谷县| 大关县| 鸡东县| 裕民县| 尉氏县| 龙口市| 徐汇区| 德庆县| 常宁市| 沧源| 南川市| 余姚市| 博客| 镇远县| 漠河县| 华容县| 库尔勒市| 闵行区| 忻城县| 曲水县| 吉林省| 延吉市| 城固县| 博湖县| 高台县| 孟村| 邢台市| 荃湾区| 阿拉尔市| 澳门| 石林| 陇西县| 丹巴县| 凤凰县| 余干县| 康保县| 德昌县| 尚志市| 横山县| 曲阜市| 正镶白旗|