0

我正在使用el-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>

到目前为止一切都很好,但是由于组件会出现在不同的页面中,所以我想提取一个自定义组件以避免重复。

根据指引

v-model="fullName"

相当于

v-bind:value="fullName"
v-on:input="$emit('input', $event)"

所以我像这样提取了选择组件:

<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>

选择下拉菜单工作正常,但不幸的是,选择没有显示我选择的选项,在我选择一个选项后它仍然是空的。我怀疑也许我应该切换v-on:input到'v-on:change',但它也不起作用。

更新我创建了一个简单的例子,你可以在这里 克隆它,请检查el-select-as-component分支。跑

npm install
npm run dev

您将看到一个包含 3 种选择的简单页面:
左侧是一个用原始选择编写的自定义组件,它工作正常。
中间一个是用 编写的自定义组件el-select,下拉列表保持为空,但是单击按钮filterForm.elClientId后您可以在控制台中看到 。Filter这就是我提出这个问题的原因。
右边的是普通的el-select,效果很好。

4

1 回答 1

4

该指南说v-model等效于v-bind:valuev-on:input但是如果您仔细观察,在侦听器函数中,绑定的变量是使用事件属性设置的。你在你的例子中所做的不一样,在你的监听器中你发出另一个事件。除非你抓住这个新事件,否则你的价值永远不会被设定。

另一件事是您不能修改道具,您应该将其视为只读变量。

如果你想从父组件监听到发出的事件到子组件,你必须做这样的事情

<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输入事件,因此v-model父级中的 将被更新。

在你的父母中,你可以像这样使用这个组件<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价值。

于 2018-06-19T09:41:06.347 回答