1. 程式人生 > >Vue JSX、自定義 v-model

Vue JSX、自定義 v-model

​部落格地址:[https://ainyi.com/92](https://ainyi.com/92) 最初用到 JSX,就是做這個部落格的時候。iview 表格元件,不支援像 element 那樣直接寫 html 程式碼渲染,只能通過 render 函式渲染,也就是 JSX 語法 這個說起來不陌生,JSX 是 react 框架的老本行了,玩 react 的同學肯定對這個也玩的很溜(最近在公司做的某些專案也是 react) 那我還是記錄一下在 Vue JSX 的使用吧 ## JSX 定義 JSX 是一種 JavaScript 的語法擴充套件,多運用於 React 架構中。==JSX = Javascript + XML==,即在 Javascript 裡面寫 XML,即具備 Javascript 的靈活性,又有 html 的語義化和直觀性 ## 應用場景 有人說,Vue 的模板語法簡單易上手,實現的功能也幾乎足夠。JSX 不好上手,寫起來程式碼量也多,用來幹啥呢 那你就忽略了 JavaScript 的靈活性了 - 一些複雜表單的實現 在這插播一個使用 vue 模板語法實現複雜表單的傳送門:[Element 動態渲染、移除表單並新增驗證 & 動態新增、移除驗證](https://ainyi.com/66) - 函式式元件 ### 函式式元件 簡單說一下函式式元件 函式式元件就是函式是元件。使用過 React 的同學,應該不會對函式式元件感到陌生 函式式元件,我們可以理解為==沒有內部狀態==,==沒有生命週期鉤子函式==,==沒有 this==(不需要例項化的元件) 在日常開發中,經常會開發一些純展示性的業務元件,比如一些詳情頁面,列表介面等,它們有一個共同的特點是隻需要將外部傳入的資料進行展現,不需要有內部狀態,不需要在生命週期鉤子函式裡面做處理,這時候你就可以考慮使用函式式元件 ```js export default { // 通過配置 functional 屬性指定元件為函式式元件 functional: true, // 元件接收的外部屬性 props: { avatar: { type: String } }, /** * 渲染函式 * @param {*} h * @param {*} context 函式式元件沒有 this, props, slots 等,都在 context 上面掛著 */ render(h, context) { const { props } = context if (props.avatar) { return } return } } ``` **使用函式式元件的原因:** 1. 最主要最關鍵的原因是函式式元件不需要例項化,無狀態,沒有生命週期,所以渲染效能要好於普通元件 2. 函式式元件結構比較簡單,程式碼結構更清晰 **函式式元件與普通元件的區別** 1. 函式式元件需要在元件上宣告==functional== 2. 函式式元件不需要例項化,所以沒有 this,==this==通過==render==函式的第二個引數來代替 3. 函式式元件沒有生命週期鉤子函式,不能使用計算屬性、watch 等等 4. 函式式元件不能通過 $emit 對外暴露事件,呼叫事件只能通過==context.listeners.click==的方式呼叫外部傳入的事件 5. 因為函式式元件是沒有例項化的,所以在外部通過==ref==去引用元件時,實際引用的是 HTMLElement 6. 函式式元件的==props==可以不用顯示宣告,所以沒有在==props==裡面宣告的屬性都會被自動隱式解析為 prop,而普通元件所有未宣告的屬性都被解析到 $attrs 裡面,並自動掛載到元件根元素上面(可以通過 inheritAttrs 屬性禁止) **模板語法宣告函式式元件** 在 Vue2.5 之前,使用函式式元件只能通過 JSX 的方式,在之後可以通過==模板語法==來宣告函式式元件 ```html ``` ## 瞭解 createElement 學習 JSX 之前,先了解 createElement 字面意思,==建立元素== 大名鼎鼎的==虛擬DOM==應該都知道吧,就是它的返回值 => 插播一個以前寫過的==VNode==傳送門:[virtual DOM](https://ainyi.com/34) 關於 createElement 方法,有三個引數: 1. 第一個引數主要用於提供 dom 的 html 內容,型別可以是字串、物件或函式。比如 “div” 就是建立一個 div 標籤 2. 第二個引數(型別是物件)主要用於設定這個 dom 的一些樣式、屬性、傳的元件的引數、繫結事件之類,具體可以參考 官方文件 裡這一小節的說明 3. 第三個引數(型別是陣列,陣列元素型別是 VNode)主要用於說是該節點下有其他結點的話,就放在這裡 使用例子: ```js export default { methods: { $_handleChangeUser(value) { this.formInline.user = value } }, render(h) { return h( 'ElForm', { props: { inline: true, model: this.formInline }, staticClass: 'demo-form-inline' }, [ h( 'ElFormItem', { props: { label: '使用者名稱' } }, [ h('ElInput', { props: { value: this.formInline.user }, attrs: { placeholder: '請輸入使用者名稱' }, on: { input: this.$_handleChangeUser } }) ] ) ] ) } } ``` 看起來寫法十分複雜,若頁面上這麼多元素,頻繁使用 createElement 方法難免程式碼臃腫,這時就應該使用 JSX 代替 createElement 了 ## JSX 我們再來用 JSX 語法重新實現上面的程式碼 ```html methods: { $_handleInputUser(value) { this.formInline.user = value } }, render(h) { return ( ) } ``` 跟 react 一模一樣了 將 h 作為 createElement 的別名 是 Vue 生態系統中的一個通用慣例,實際上也是 JSX 所要求的 從 Vue 的 Babel 外掛的 3.4.0 版本開始,我們會在以 ES2015 語法宣告的含有 JSX 的任何方法和 getter 中 (不是函式或箭頭函式中) 自動注入==const h = this.$createElement==,這樣就可以去掉 (h) 引數了。對於更早版本的外掛,如果 h 在當前作用域中不可用,應用會報錯 ## Vue JSX 中指令的使用 我們使用 Vue 模板語法,指令用的爽歪歪,像 v-model, v-if, v-for, @, 插槽等等 但是,這些都在 JSX 中無法使用。那麼如何實現相同的功能呢 > **注意:新版 vue-cli4 中,已經預設集成了 JSX 語法對 v-model 的支援,可以直接使用 `````` 如果你的專案比較老,也可以安裝外掛 babel-plugin-jsx-v-model 來進行支援** ### 自定義 v-model v-model 是 Vue 提供的一個語法糖,它本質上是由 value 屬性 + input 事件組成的(都是原生的預設屬性) 所以在 JSX 中,我們可以通過傳遞 value 屬性並監聽 input 事件來實現資料的雙向繫結 ```js export default { data() { return { name: '' } }, methods: { // 監聽 onInput 事件進行賦值操作 $_handleInput(e) { this.name = e.target.value } }, render() { // 傳遞 value 屬性 並監聽 onInput事件 return } } ```
**封裝元件**如下: **子元件** ```html ``` **父元件** ```html ``` **再次重申**:新版 vue-cli4 中,已經預設集成了 JSX 語法對 v-model 的支援,可以直接使用 `````` ### el-form 的 :model 屬性 注意 el-form 的 :model 屬性,在 JSX 中是這樣寫的 ```props={{ model: this.data }}```,比較特別