提取自定义组件时如何让el-select和v-model协同工作
how to make el-select and v-model work together when extracting a custom component
我正在使用 el-select 构建一个 select 组件。像这样:
<template>
//omitted code
<el-select v-model="filterForm.client"
filterable
remote
placeholder="Please enter a keyword"
:remote-method="filterClients"
:loading="loading">
<el-option
v-for="item in clientCandidates"
:key="item._id"
:label="item.name"
:value="item._id">
</el-option>
</el-select>
</template>
<scripts>
export default {
data() {
filterForm: {
client: ''
},
clientCandidates: [],
loading: false
},
methods: {
filterClients(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false;
this.clientCandidates = [{_id: '1', name: 'foo'}, {_id: '2', name: 'bar'}];
}, 200);
} else {
this.clientCandidates = [];
}
}
}
}
</scripts>
到目前为止一切顺利,但是由于组件会出现在不同的页面中,所以我想提取一个自定义组件以避免重复。
根据 guideline、
v-model="fullName"
等同于
v-bind:value="fullName"
v-on:input="$emit('input', $event)"
所以我提取了 select 组件,如下所示:
<template>
<el-select
v-bind:value="clientId"
v-on:input="$emit('input', $event)"
placeholder="Filter by short name"
filterable="true"
remote="true"
:remote-method="filter"
:loading="loading">
<el-option
v-for="item in clients"
:key="item._id"
:label="item.name"
:value="item._id">
</el-option>
</el-select>
</template>
<scripts>
export default {
props: {
clientId: {
type: String,
required: true
}
},
data() {
return {
clients: [],
loading: false,
}
},
methods: {
filter(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false;
this.clients = [{_id: '1', name: 'foo'}, {_id: '2', name: 'bar'}];
}, 200);
} else {
this.clients = [];
}
}
}
}
</scripts>
父组件如下所示:
<select-client v-model="filterForm.clientId"></select-client>
select 下拉列表工作正常,但不幸的是,select 没有显示我 select 编辑的选项,在我选择一个选项后它仍然是空的。我怀疑也许我应该将 v-on:input
切换为 'v-on:change',但它也不起作用。
更新
我创建了一个简单的示例,您可以克隆它 here,请查看 el-select-as-component
分支。 运行
npm install
npm run dev
您将看到一个简单的页面,其中包含 3 种 select:
左边的是一个用raw select 编写的自定义组件,它工作正常。
中间一个是用el-select
编写的自定义组件,下拉列表仍然是空的,但是单击Filter
按钮后,您可以在控制台中看到filterForm.elClientId
。这就是我提出这个问题的原因。
右边的是普通的el-select
,很好用
指南说 v-model
等同于 v-bind:value
和 v-on:input
但如果你仔细观察,在侦听器函数中,绑定的变量是用事件设置的 属性.你在你的例子中所做的是不一样的,在你的听众中你发出另一个事件。除非你抓住这个新事件,否则你的价值将永远不会被设置。
另一件事是你不能修改道具,你应该把它当作一个 read-only 变量。
如果你想从 parent 监听到 child 组件发出的事件,你必须做这样的事情
<template>
<el-select
:value="selected"
@input="dispatch"
placeholder="Filter by short name"
:filterable="true"
:remote="true"
:remote-method="filter"
:loading="loading">
<el-option
v-for="item in clients"
:key="item._id"
:label="item.name"
:value="item._id">
</el-option>
</el-select>
</template>
<script>
export default {
name: 'SelectClient',
data() {
return {
selected: '',
clients: [],
loading: false,
}
},
methods: {
filter(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false
this.clients = [{_id: '1', name: 'foo'}, {_id: '2', name: 'bar'}]
}, 200)
} else {
this.clients = []
}
},
dispatch (e) {
this.$emit('input', e)
this.selected = e
}
}
}
</script>
注意:v-model
+ watch
模式也可以。重要的是$emit
输入事件,所以parent中的v-model
会被更新。
并且在您的 parent 中,您可以像这样使用此组件:<select-client v-model="clientId"/>
。
提示:如果你想在不同的地方修改相同的数据,你应该有一个单一的真实来源并且更喜欢vuex。那么你的组件将是这样的
<template lang="html">
<select
v-model="clientId">
<option
disabled
value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</template>
<script>
export default {
data () {
return {
clientId: ''
}
},
watch: {
clientId (newValue) {
// Do something else here if you want then commit it
// Of course, listen for the 'setClientId' mutation in your store
this.$store.commit('setClientId', newValue)
}
}
}
</script>
然后在你的其他组件中,你可以监听$store.state.clientId
值。
我正在使用 el-select 构建一个 select 组件。像这样:
<template>
//omitted code
<el-select v-model="filterForm.client"
filterable
remote
placeholder="Please enter a keyword"
:remote-method="filterClients"
:loading="loading">
<el-option
v-for="item in clientCandidates"
:key="item._id"
:label="item.name"
:value="item._id">
</el-option>
</el-select>
</template>
<scripts>
export default {
data() {
filterForm: {
client: ''
},
clientCandidates: [],
loading: false
},
methods: {
filterClients(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false;
this.clientCandidates = [{_id: '1', name: 'foo'}, {_id: '2', name: 'bar'}];
}, 200);
} else {
this.clientCandidates = [];
}
}
}
}
</scripts>
到目前为止一切顺利,但是由于组件会出现在不同的页面中,所以我想提取一个自定义组件以避免重复。
根据 guideline、
v-model="fullName"
等同于
v-bind:value="fullName"
v-on:input="$emit('input', $event)"
所以我提取了 select 组件,如下所示:
<template>
<el-select
v-bind:value="clientId"
v-on:input="$emit('input', $event)"
placeholder="Filter by short name"
filterable="true"
remote="true"
:remote-method="filter"
:loading="loading">
<el-option
v-for="item in clients"
:key="item._id"
:label="item.name"
:value="item._id">
</el-option>
</el-select>
</template>
<scripts>
export default {
props: {
clientId: {
type: String,
required: true
}
},
data() {
return {
clients: [],
loading: false,
}
},
methods: {
filter(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false;
this.clients = [{_id: '1', name: 'foo'}, {_id: '2', name: 'bar'}];
}, 200);
} else {
this.clients = [];
}
}
}
}
</scripts>
父组件如下所示:
<select-client v-model="filterForm.clientId"></select-client>
select 下拉列表工作正常,但不幸的是,select 没有显示我 select 编辑的选项,在我选择一个选项后它仍然是空的。我怀疑也许我应该将 v-on:input
切换为 'v-on:change',但它也不起作用。
更新
我创建了一个简单的示例,您可以克隆它 here,请查看 el-select-as-component
分支。 运行
npm install
npm run dev
您将看到一个简单的页面,其中包含 3 种 select:
左边的是一个用raw select 编写的自定义组件,它工作正常。
中间一个是用el-select
编写的自定义组件,下拉列表仍然是空的,但是单击Filter
按钮后,您可以在控制台中看到filterForm.elClientId
。这就是我提出这个问题的原因。
右边的是普通的el-select
,很好用
指南说 v-model
等同于 v-bind:value
和 v-on:input
但如果你仔细观察,在侦听器函数中,绑定的变量是用事件设置的 属性.你在你的例子中所做的是不一样的,在你的听众中你发出另一个事件。除非你抓住这个新事件,否则你的价值将永远不会被设置。
另一件事是你不能修改道具,你应该把它当作一个 read-only 变量。
如果你想从 parent 监听到 child 组件发出的事件,你必须做这样的事情
<template>
<el-select
:value="selected"
@input="dispatch"
placeholder="Filter by short name"
:filterable="true"
:remote="true"
:remote-method="filter"
:loading="loading">
<el-option
v-for="item in clients"
:key="item._id"
:label="item.name"
:value="item._id">
</el-option>
</el-select>
</template>
<script>
export default {
name: 'SelectClient',
data() {
return {
selected: '',
clients: [],
loading: false,
}
},
methods: {
filter(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false
this.clients = [{_id: '1', name: 'foo'}, {_id: '2', name: 'bar'}]
}, 200)
} else {
this.clients = []
}
},
dispatch (e) {
this.$emit('input', e)
this.selected = e
}
}
}
</script>
注意:v-model
+ watch
模式也可以。重要的是$emit
输入事件,所以parent中的v-model
会被更新。
并且在您的 parent 中,您可以像这样使用此组件:<select-client v-model="clientId"/>
。
提示:如果你想在不同的地方修改相同的数据,你应该有一个单一的真实来源并且更喜欢vuex。那么你的组件将是这样的
<template lang="html">
<select
v-model="clientId">
<option
disabled
value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</template>
<script>
export default {
data () {
return {
clientId: ''
}
},
watch: {
clientId (newValue) {
// Do something else here if you want then commit it
// Of course, listen for the 'setClientId' mutation in your store
this.$store.commit('setClientId', newValue)
}
}
}
</script>
然后在你的其他组件中,你可以监听$store.state.clientId
值。