在前端平常的業務中,無論是官網、展示頁還是後臺運營系統都離不開表單,它承載了大部分的資料採集工作。所以如何更好地實現它,是平常工作中的一個重要問題。
在應用Vue框架去開發業務時,會將頁面上每個獨立的可視/可互動區域拆分為一個元件,再通過多個元件的自由組合來組成新的頁面。例如
<template>
<header></header>
...
<content></content>
...
<footer></footer>
</template>
複製程式碼
當使用者的某個行為觸發表單時(例如註冊、建立內容等),期望在頁面中彈出一個From
元件。通常的做法是在template
中填入一個<form>
元件用於開發,並通過控制data
中的UI.isOpen
來對其display
進行控制,例如在當前<template>
元件內開發<register-form>
。
<template>
<header></header>
...
<content></content>
...
<footer></footer>
...
<register-form v-if="UI.isOpen">
<form-item></form-item>
...
<submit-button></submit-button>
</register-form>
</template>
複製程式碼
這樣開發有一點優勢,Form
元件與其父元件之間可以通過prop
以及$emit
方便通訊。但是也會有以下幾個缺陷:
- 當前元件的
data
必須要有UI.isOpen
來控制表單,如果存在多個表單時,就會有大量的狀態來維護表單的開關; - 如果表單多次彈出時,可能需要對錶單的
data
進行重置; - 與元件化思想相違背,表單不屬於當前頁面,它只是由於使用者行為觸發的結果。
為了解決以上缺陷,並且還能具備方便通訊的優勢,本文選擇用Vue.extend
將原有<form>
元件轉化為method function
,並維護在當前元件的method
中,當使用者觸發時,在頁面中掛載,關閉時自動登出。
例項
演示地址:演示例項
程式碼地址:FatGe github
- APP元件
<template>
<div id="app">
<el-button
type="primary" icon="el-icon-edit-outline"
@click="handleClick"
>註冊</el-button>
</div>
</template>
<script>
import register from './components/register'
import { transform } from './transform'
export default {
name: 'App',
methods: {
register: transform(register),
handleClick () {
this.register({
propsData: { name: '皮鞋' },
done: name => alert(`${name}牛B`)
})
}
}
}
</script>
複製程式碼
當<el-button>
的點選事件觸發時,呼叫register
方法,將表單元件掛載在頁面中。
- Form元件
<template>
<div class="mock" v-if="isVisible">
<div class="form-wrapper">
<i class="el-icon-close close-btn" @click.stop="close"></i>
...<header />
...<content />
<div class="footer">
<el-button
type="primary"
@click="handleClick"
>確定</el-button>
<el-button
type="primary"
@click="handleClick"
>取消</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
porps: { ... },
data () {
return {
isVisible: true
}
},
watch: {
isVisible (newValue) {
if (!newValue) {
this.destroyElement()
}
}
},
methods: {
handleClick ({ type }) {
const handler = {
close: () => this.close()
}
},
destroyElement () {
this.$destroy()
},
close () {
this.isVisible = false
}
},
mounted () {
document.body.appendChild(this.$el)
},
destroyed () {
this.$el.parentNode.removeChild(this.$el)
}
}
</script>
複製程式碼
在APP元件內並未維護<form>
元件的狀態,其開啟或關閉只維護在自身的data
中。
原理
上述程式碼中,最為關鍵的一步就是transform
函式,它將原有的`