场景:子组件有 loading,但状态由父组件控制,那 loading 由谁维护呢?
常规做法:传递
父组件维护 loading,传递给子组件。
child.vue
<el-button :loading="loading" @click="query">查询</el-button>
export default {
props: {
loading: Boolean
},
methods: {
query() {
const obj = { data: 'xxx' }
this.$emit('query', obj)
}
}
}
parent.vue
<child :loading="loading" @query="query" />
export default {
data() {
return {
loading: false
}
},
methods: {
async query(obj) {
try {
this.loading = true
const res = await HTTP.query(obj.data)
//
} catch (error) {
//
} finally {
this.loading = false
}
}
}
}
另一种做法:劫持
子组件自己维护 loading,父组件改变子组件传来的对象的属性,子组件劫持该对象属性的改变。
child.vue
<el-button :loading="loading" @click="query">查询</el-button>
export default {
data() {
return {
loading: false
}
},
methods: {
query() {
const obj = { data: 'xxx' }
Object.defineProperty(obj, 'loading', {
set: val => {
this.loading = val
}
})
this.$emit('query', obj)
}
}
}
以上是利用 Object.defineProperty 监听对象的属性,也可以使用 ES6 的 Proxy。
query() {
const obj = new Proxy(
{ data: 'xxx' },
{
set: (target, propKey, value, receiver) => {
if (propKey === 'loading') this.loading = value
return Reflect.set(target, propKey, value, receiver)
}
}
)
this.$emit('query', obj)
}
parent.vue
<child @query="query" />
export default {
methods: {
async query(obj) {
try {
obj.loading = true
const res = await HTTP.query(obj.data)
//
} catch (error) {
//
} finally {
obj.loading = false
}
}
}
}
尤其当子组件有多个时这种方式就比较好维护。
<child v-for="item in list" :key="item.id" :data="item" @query="query" />