Vuejs2 如何使el select和v-model在提取自定义组件时协同工作

Vuejs2 如何使el select和v-model在提取自定义组件时协同工作,vuejs2,vue-component,element-ui,Vuejs2,Vue Component,Element Ui,我正在使用来构建一个select组件。大概是这样的: <template> //omitted code <el-select v-model="filterForm.client" filterable remote placeholder="Please enter a keyword" :remot

我正在使用来构建一个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>
<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-bind:value="fullName"
v-on:input="$emit('input', $event)"
因此,我提取了选择组件,如下所示:

<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>
<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>
您将看到一个包含3种选择的简单页面:
左侧是一个用原始选择编写的自定义组件,工作正常。
中间的一个是在
el select
中编写的自定义组件,下拉列表仍然为空,但单击
Filter
按钮后,您可以在控制台中看到
filterForm.elClientId
。这就是我提出这个问题的原因。

右边的是一个普通的
el-select
,它工作得很好。

指南说
v-model
相当于
v-bind:value
v-on:input
,但是如果仔细观察,在侦听器函数中,变量binded是用事件属性设置的。您在示例中所做的不一样,在侦听器中您发出另一个事件。除非捕获此新事件,否则将永远不会设置您的值

另一件事是你不能修改道具,你应该把它看作是只读变量。< /P> 如果您想从父组件监听子组件中发出的事件,必须执行以下操作

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

指南说
v-model
相当于
v-bind:value
v-on:input
,但是如果您仔细观察,在侦听器函数中,binded变量是用事件属性设置的。您在示例中所做的不一样,在侦听器中您发出另一个事件。除非捕获此新事件,否则将永远不会设置您的值

另一件事是你不能修改道具,你应该把它看作是只读变量。< /P> 如果您想从父组件监听子组件中发出的事件,必须执行以下操作

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

请?@JacobGoh谢谢,我已经用github示例更新了问题。我完成了您的回购,并在这里为您制作了PR>请?@JacobGoh谢谢,我用一个github示例更新了这个问题。我完成了你的回购,并在这里为你做了公关>谢谢你的回复。我试过你的代码,它不起作用。控制台告诉我
未定义的selectedOptions
,我认为
el select
会转换原始事件,因此
事件。目标
不再存在。我对前端非常陌生,所以可能会弄错:-(只是一个注释:“this.selected=e”在
中,dispatch
也是非常重要的,我相信
没有得到很好的实现,因为对于
,我不必设置
这个。value=e
明确地感谢您。我一直在寻找完全相同的解决方案……我也在使用元素UI。el select组件有点混乱,因为您不知道lly是触发输入事件的el select,或el选项。事实上,我认为它们都在触发事件,但最好的方法是只查看顶层。我看了一下元素ui源代码,也有一种很好的事件传播方式,但代码可能看起来有点过于复杂,还有其他东西。也许我会当我有更多的时间时,再多写一点代码(aka..never;P)非常感谢!我正在构建一个类似的组件,突然,我发现当您通过代码删除或设置一个值时,组件本身没有刷新
filterForm.clientId=null
,我指的是选择的变量
。为了修复这种情况,我必须在组件本身添加一个手表,例如下面:
watch:{'value':函数(pnew,pold){if(pnew==null)this.selected=null;}
谢谢你的回复。我尝试了你的代码,但它不起作用。控制台告诉我
未定义的selectedOptions
,我认为
el select
转换原始事件,因此
event.target
不再存在。我对前端非常陌生,因此可能会出错:-(只需注意:“this.selected=e”在
中,dispatch
也是非常重要的,我相信
没有得到很好的实现,因为对于
,我不必设置
这个。value=e
明确地感谢您。我一直在寻找完全相同的解决方案……我也在使用元素UI。el select组件有点混乱,因为您不知道lly是触发输入事件的el select,或el选项。事实上,我认为它们都在触发事件,但最好的方法是只查看顶层。我看了一下元素ui源代码,也有一种很好的事件传播方式,但代码可能看起来有点过于复杂,还有其他东西。也许我会当我有更多的时间时,再多写一点代码(aka..never;P)非常感谢!我正在构建一个类似的组件,突然,我发现当您通过代码删除或设置一个值时,组件本身没有刷新
filterForm.clientId=null
,我指的是选择的变量
。为了修复这种情况,我必须在组件本身添加一个手表,例如下面:
watch:{'value':函数(pnew,pold){if(pnew==null)this.selected=null;}}