解決Antd輸入框卡頓問題以及Pubsub.js的使用方式
項(xiàng)目場景
項(xiàng)目中通過表單來填寫校驗(yàn)大量復(fù)雜數(shù)據(jù)
問題描述
項(xiàng)目中使用的是Ant Design of Vue這個(gè)組件庫,使用FormModel 表單,數(shù)據(jù)字段和校驗(yàn)較多時(shí),表單操作卡頓;eg: a-input輸入框,等你輸入完字及,幾秒后才慢慢出現(xiàn)你輸入的字符
原因分析
vue在進(jìn)行輸入時(shí),進(jìn)行了多次的render刷新渲染操作,導(dǎo)致了input框輸入時(shí)發(fā)生的卡頓現(xiàn)象
解決方案
官方給出的解決辦法,將 Form 相關(guān)的業(yè)務(wù)獨(dú)立到一個(gè)單獨(dú)的組件中,減少組件渲染的消耗,如果有很多校驗(yàn)項(xiàng),可把它們分別放在不同的Form中處理
eg :
一、組件封裝

將大表單拆分成三個(gè)組件表單,數(shù)據(jù)校驗(yàn)等操作在其組件內(nèi)部實(shí)現(xiàn)
二、formTable中的字段有部分與formTableTwo聯(lián)動(dòng)
這里使用PubSub.js進(jìn)行兄弟組件傳值
PubSub.js的使用
1.首先安裝pubsub-js
npm install --save pubsub-js
2.簡單使用
導(dǎo)入
import PubSub from 'pubsub-js'
- 發(fā)送消息:
PubSub.publish(名稱,參數(shù)) - 訂閱消息:
PubSub.subscrib(名稱,函數(shù)) - 取消訂閱:
PubSub.unsubscrib(名稱)
在formTableTwo中使用PubSub.publish(名稱,參數(shù))發(fā)送信息,formTableOne中使用PubSub.subscrib(名稱,函數(shù))接收信息。
注意:
1.PubSub.subscrib(名稱,函數(shù))接收信息的所傳名稱要與PubSub.publish(名稱,參數(shù))發(fā)送信息的名稱一致
2.PubSub.subscrib(名稱,函數(shù))接收信息可能會(huì)被觸發(fā)多次,可以在PubSub.subscrib(名稱,函數(shù))前使用 PubSub.unsubscribe可以解決
created () {
// console.log('form1', this.form)
// 解決PubSub多次調(diào)用
PubSub.unsubscribe('send');
// 訂閱消息(接收消息)
PubSub.subscribe('send', (name, value) => {
console.log('name', name)
console.log('value', value)
})
// 訂閱組件二的消息
PubSub.subscribe('sendTwo', (name, val) => {
console.log('sendTwo', name)
console.log('我是接受到的值', val)
this.isShow = val
})
console.log('this.form', this.form)
},
3.記得發(fā)布了消息 要在vue beforedestory 中銷毀取消訂閱 ,發(fā)布的次數(shù)多了,會(huì)造成訂閱一次觸發(fā)多次的情況;
beforeDestroy () {
PubSub.unsubscribe('send')
PubSub.unsubscribe('sendTwo')
}
三、使用Promise.all提交校驗(yàn)表單
子組件
onSubmit () {
return new Promise((resolve, reject) => {
this.$refs.ruleForm.validate(valid => {
if (valid) {
console.log('表單1通過')
this.outgoingInfo()
resolve(valid)
} else {
console.log('error submit!!')
reject(valid)
return false
}
})
})
},
父組件
// 表單校驗(yàn)
submitForm () {
console.log('this.$refs.FormTableOne.form', this.$refs.FormTableOne.form)
const rules1 = this.$refs.FormTableOne.onSubmit()
const rules2 = this.$refs.FormTableTwo.onSubmit()
const rules3 = this.$refs.FormTableThree.onSubmit()
Promise.all([rules1,rules2, rules3]).then(() => {
console.log('校驗(yàn)通過')
})
},
完整demo
formGroup
<template>
<div>
<div>
<FormTableOne ref="FormTableOne" :formInfo="form" @outgoingInfo="outgoingInfo"/>
<FormTableTwo ref="FormTableTwo" />
<FormTableThree ref="FormTableThree" />
</div>
<a-button type="primary" @click="submitForm">
submit
</a-button>
<a-button style="margin-left: 10px;" @click="resetForm">
Reset
</a-button>
</div>
</template>
<script>
import FormTableOne from './components/formTableOne'
import FormTableTwo from './components/formTableTwo'
import FormTableThree from './components/formTableThree'
import PubSub from 'pubsub-js'
export default {
components: {
FormTableOne,
FormTableTwo,
FormTableThree
},
data () {
return {
form: {}
}
},
created() {
this.sendMessages()
setTimeout(() => {
this.form = {
name1: '123456',
region1: undefined,
date1: undefined,
delivery1: false,
type1: [],
resource1: '123',
desc1: '123',
name2: '',
region2: undefined,
date2: undefined,
delivery2: false,
type2: [],
resource2: '',
desc2: '',
name3: '',
region3: undefined,
date3: undefined,
delivery3: false,
type3: [],
resource3: '',
desc3: ''
}
}, 2000)
},
methods: {
// 表單校驗(yàn)
submitForm () {
console.log('this.$refs.FormTableOne.form', this.$refs.FormTableOne.form)
const rules1 = this.$refs.FormTableOne.onSubmit()
const rules2 = this.$refs.FormTableTwo.onSubmit()
const rules3 = this.$refs.FormTableThree.onSubmit()
Promise.all([rules1,rules2, rules3]).then(() => {
console.log('校驗(yàn)通過')
})
},
outgoingInfo (val) {
console.log('組件一傳出的值', val)
Object.assign(this.form, val)
console.log('主組件的值', this.form)
},
resetForm () {
this.sendMessages()
this.form = {
name1: '',
region1: undefined,
date1: undefined,
delivery1: false,
type1: [],
resource1: '',
desc1: '',
name2: '',
region2: undefined,
date2: undefined,
delivery2: false,
type2: [],
resource2: '',
desc2: '',
name3: '',
region3: undefined,
date3: undefined,
delivery3: false,
type3: [],
resource3: '',
desc3: ''
}
console.log('this.form', this.form)
},
sendMessages () {
console.log('發(fā)送')
PubSub.publish('send', {
name: '張三',
age: 18
})
}
}
}
</script>
<style></style>
formTableOne
<template>
<div>
<a-form-model
ref="ruleForm"
:model="form"
:rules="rules"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-model-item ref="name1" label="組件一: name" prop="name1" v-if="isShow">
<a-input
v-model="form.name1"
@blur="
() => {
$refs.name1.onFieldBlur()
}
"
/>
</a-form-model-item>
<a-form-model-item label="組件一: zone" prop="region1">
<a-select v-model="form.region1" placeholder="please select your zone">
<a-select-option value="shanghai">
Zone one
</a-select-option>
<a-select-option value="beijing">
Zone two
</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="組件一: time" required prop="date1">
<a-date-picker
v-model="form.date1"
show-time
type="date"
placeholder="Pick a date"
style="width: 100%;"
/>
</a-form-model-item>
<a-form-model-item label="組件一: delivery1" prop="delivery1">
<a-switch v-model="form.delivery1" />
</a-form-model-item>
<a-form-model-item label="組件一: type1" prop="type1">
<a-checkbox-group v-model="form.type1">
<a-checkbox value="1" name="type1">
Online
</a-checkbox>
<a-checkbox value="2" name="type1">
Promotion
</a-checkbox>
<a-checkbox value="3" name="type1">
Offline
</a-checkbox>
</a-checkbox-group>
</a-form-model-item>
<a-form-model-item label="組件一:Resource1s" prop="resource1">
<a-radio-group v-model="form.resource1">
<a-radio value="1">
Sponsor
</a-radio>
<a-radio value="2">
Venue
</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="組件一: form" prop="desc1">
<a-input v-model="form.desc1" type="textarea" />
</a-form-model-item>
<a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
</a-form-model-item>
</a-form-model>
<a-button type="primary" @click="outgoingInfo">
Create
</a-button>
</div>
</template>
<script>
import PubSub from 'pubsub-js'
const list = [
'',
'name1',
'region1',
'date1',
'delivery1',
'type1',
'resource1',
'desc1'
]
export default {
name: 'FormTableOne',
props: {
formInfo: {
type: Object,
default: () => {
return {
name1: '',
region1: undefined,
date1: undefined,
delivery1: false,
type1: [],
resource1: '',
desc1: ''
}
}
}
},
created () {
// console.log('form1', this.form)
// 解決PubSub多次調(diào)用
PubSub.unsubscribe('send');
// 訂閱消息(接收消息)
PubSub.subscribe('send', (name, value) => {
console.log('name', name)
console.log('value', value)
})
// 訂閱組件二的消息
PubSub.subscribe('sendTwo', (name, val) => {
console.log('sendTwo', name)
console.log('我是接受到的值', val)
this.isShow = val
})
console.log('this.form', this.form)
},
data () {
return {
isShow: true,
labelCol: { span: 4 },
wrapperCol: { span: 14 },
other: '',
form: {
name1: '',
region1: undefined,
date1: undefined,
delivery1: false,
type1: [],
resource1: '',
desc1: ''
},
rules: {
region1: [
{
required: true,
message: 'Please select Activity zone',
trigger: 'change'
}
],
date1: [
{ required: true, message: 'Please pick a date', trigger: 'change' }
],
resource1: [
{
required: true,
message: 'Please select activity resource1',
trigger: 'change'
}
],
desc1: [
{
required: true,
message: 'Please input activity form',
trigger: 'blur'
}
]
}
}
},
watch: {
// 過濾一些不屬于這個(gè)組件屬性
formInfo () {
let obj = JSON.parse(JSON.stringify(this.formInfo, (key, value) => {
if (list.includes(key)) {
return value
} else {
return undefined
}
}))
this.form = Object.assign(this.form, obj)
},
deep: true
},
computed: {
},
methods: {
onSubmit () {
return new Promise((resolve, reject) => {
this.$refs.ruleForm.validate(valid => {
if (valid) {
console.log('表單1通過')
this.outgoingInfo()
resolve(valid)
} else {
console.log('error submit!!')
reject(valid)
return false
}
})
})
},
resetForm () {
this.$refs.ruleForm.resetFields()
},
// 將組件的值傳出去
outgoingInfo () {
this.$emit('outgoingInfo', this.form)
}
},
beforeDestroy () {
PubSub.unsubscribe('send')
PubSub.unsubscribe('sendTwo')
}
}
</script>
formTabeTwo
<template>
<a-form-model
ref="ruleForm"
:model="form"
:rules="rules"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-model-item ref="name2" label="組件二: name" prop="name2">
<a-input
v-model="form.name2"
@blur="
() => {
$refs.name2.onFieldBlur()
}
"
/>
</a-form-model-item>
<a-form-model-item label="組件二: zone" prop="region2">
<a-select v-model="form.region2" placeholder="please select your zone">
<a-select-option value="shanghai">
Zone one
</a-select-option>
<a-select-option value="beijing">
Zone two
</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="組件二: time" required prop="date2">
<a-date-picker
v-model="form.date2"
show-time
type="date"
placeholder="Pick a date"
style="width: 100%;"
/>
</a-form-model-item>
<a-form-model-item label="組件二: delivery2" prop="delivery2">
<a-switch v-model="form.delivery2" @change="checkChange"/>
</a-form-model-item>
<a-form-model-item label="組件二: type2" prop="type2">
<a-checkbox-group v-model="form.type">
<a-checkbox value="1" name="type2">
Online
</a-checkbox>
<a-checkbox value="2" name="type2">
Promotion
</a-checkbox>
<a-checkbox value="3" name="type2">
Offline
</a-checkbox>
</a-checkbox-group>
</a-form-model-item>
<a-form-model-item label="組件二:resource2s" prop="resource2">
<a-radio-group v-model="form.resource2">
<a-radio value="1">
Sponsor
</a-radio>
<a-radio value="2">
Venue
</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="組件二: form" prop="desc2">
<a-input v-model="form.desc2" type="textarea" />
</a-form-model-item>
<a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
</a-form-model-item>
</a-form-model>
</template>
<script>
import PubSub from 'pubsub-js'
export default {
name: 'FormTableOne',
data () {
return {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
other: '',
form: {
name2: '',
region2: undefined,
date2: undefined,
delivery2: false,
type2: [],
resource2: '',
desc2: ''
},
rules: {
region2: [
{
required: true,
message: 'Please select Activity zone',
trigger: 'change'
}
],
date2: [
{ required: true, message: 'Please pick a date', trigger: 'change' }
],
resource2: [
{
required: true,
message: 'Please select activity resource2',
trigger: 'change'
}
],
desc2: [
{
required: true,
message: 'Please input activity form',
trigger: 'blur'
}
]
}
}
},
created() {
},
methods: {
onSubmit () {
return new Promise((resolve, reject) => {
this.$refs.ruleForm.validate(valid => {
if (valid) {
console.log('表單2通過')
resolve(valid)
} else {
console.log('error submit!!')
reject(valid)
return false
}
})
})
},
checkChange() {
// 發(fā)布消息
PubSub.publish('sendTwo', false)
},
resetForm () {
this.$refs.ruleForm.resetFields()
}
}
}
</script>
formTableThree
<template>
<a-form-model
ref="ruleForm"
:model="form"
:rules="rules"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-model-item ref="name3" label="組件三: name3" prop="name3">
<a-input
v-model="form.name3"
@blur="
() => {
$refs.name3.onFieldBlur()
}
"
/>
</a-form-model-item>
<a-form-model-item label="組件三: zone" prop="region3">
<a-select v-model="form.region3" placeholder="please select your zone">
<a-select-option value="shanghai">
Zone one
</a-select-option>
<a-select-option value="beijing">
Zone two
</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="組件三: time" required prop="date3">
<a-date-picker
v-model="form.date3"
show-time
type="date"
placeholder="Pick a date"
style="width: 100%;"
/>
</a-form-model-item>
<a-form-model-item label="組件三: delivery3" prop="delivery3">
<a-switch v-model="form.delivery3" />
</a-form-model-item>
<a-form-model-item label="組件三: type3" prop="type3">
<a-checkbox-group v-model="form.type">
<a-checkbox value="1" name="type3">
Online
</a-checkbox>
<a-checkbox value="2" name="type3">
Promotion
</a-checkbox>
<a-checkbox value="3" name="type3">
Offline
</a-checkbox>
</a-checkbox-group>
</a-form-model-item>
<a-form-model-item label="組件三:Resource3s" prop="resource3">
<a-radio-group v-model="form.resource3">
<a-radio value="1">
Sponsor
</a-radio>
<a-radio value="2">
Venue
</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="組件三: form" prop="desc3">
<a-input v-model="form.desc3" type="textarea" />
</a-form-model-item>
<a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
</a-form-model-item>
</a-form-model>
</template>
<script>
export default {
name: 'FormTableOne',
data () {
return {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
other: '',
form: {
name3: '',
region3: undefined,
date3: undefined,
delivery3: false,
type3: [],
resource3: '',
desc3: ''
},
rules: {
region3: [
{
required: true,
message: 'Please select Activity zone',
trigger: 'change'
}
],
date3: [
{ required: true, message: 'Please pick a date', trigger: 'change' }
],
resource3: [
{
required: true,
message: 'Please select activity resource3',
trigger: 'change'
}
],
desc3: [
{
required: true,
message: 'Please input activity form',
trigger: 'blur'
}
]
}
}
},
methods: {
onSubmit () {
return new Promise((resolve, reject) => {
this.$refs.ruleForm.validate(valid => {
if (valid) {
console.log('表單3通過')
resolve(valid)
} else {
console.log('error submit!!')
reject(valid)
return false
}
})
})
},
resetForm () {
this.$refs.ruleForm.resetFields()
}
}
}
</script>
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vant?Weapp組件picker選擇器初始默認(rèn)選中問題
這篇文章主要介紹了Vant?Weapp組件picker選擇器初始默認(rèn)選中問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
vue3結(jié)合typescript中使用class封裝axios
這篇文章主要為大家介紹了vue3結(jié)合typescript中使用class封裝axios實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
聊聊vue生命周期鉤子函數(shù)有哪些,分別什么時(shí)候觸發(fā)
這篇文章主要介紹了聊聊vue生命周期鉤子函數(shù)有哪些,分別什么時(shí)候觸發(fā)?具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
vue.js將時(shí)間戳轉(zhuǎn)化為日期格式的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue.js將時(shí)間戳轉(zhuǎn)化為日期格式的實(shí)現(xiàn)代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06
vue路由守衛(wèi)及路由守衛(wèi)無限循環(huán)問題詳析
這篇文章主要給大家介紹了關(guān)于vue路由守衛(wèi)及路由守衛(wèi)無限循環(huán)問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
在vue項(xiàng)目創(chuàng)建的后初始化首次使用stylus安裝方法分享
下面小編就為大家分享一篇在vue項(xiàng)目創(chuàng)建的后初始化首次使用stylus安裝方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01

