我创建了一个自定义指令来处理VueJs中的select2。当我将select绑定到我的viewmodel中的data属性时,下面的代码可以工作,该属性不是数据中对象的属性。
与this.userId类似,但是如果它绑定到像this.user.id这样的东西,它就不会更新我的viewmodel数据对象中的值。
Vue.directive('selected', {
bind: function (el, binding, vnode) {
var key = binding.expression;
var select = $(el);
select.select2();
vnode.context.$data[binding.expression] = select.val();
select.on('change', function () {
vnode.context.$data[binding.expression] = select.val();
});
},
update: function (el, binding, newVnode, oldVnode) {
var select = $(el);
select.val(binding.value).trigger('change');
}
});
<select v-selected="userEditor.Id">
<option v-for="user in users" v-bind:value="user.id" >
{{ user.fullName}}
</option>
</select>
答案 0 :(得分:1)
当您使用第一级$data
&#39; s属性时,它会直接通过$data
访问[]
对象 - 括号
但是你想传递给selected
- 指向嵌套对象的路径,所以你应该做这样的事情:
// source: https://stackoverflow.com/a/6842900/8311719
function deepSet(obj, value, path) {
var i;
path = path.split('.');
for (i = 0; i < path.length - 1; i++)
obj = obj[path[i]];
obj[path[i]] = value;
}
Vue.directive('selected', {
bind: function (el, binding, vnode) {
var select = $(el);
select.select2();
deepSet(vnode.context.$data, select.val(), binding.expression);
select.on('change', function () {
deepSet(vnode.context.$data, select.val(), binding.expression);
});
},
update: function (el, binding, newVnode, oldVnode) {
var select = $(el);
select.val(binding.value).trigger('change');
}
});
<select v-selected="userEditor.Id">
<option v-for="user in users" v-bind:value="user.id" >
{{ user.fullName}}
</option>
</select>
假设我们有两个$data
道具:valOrObjectWithoutNesting
和objLvl1
:
data: function(){
return{
valOrObjectWithoutNesting: 'let it be some string',
objLvl1:{
objLvl2:{
objLvl3:{
objField: 'primitive string'
}
}
}
}
}
具有第一级$ data&#39; s-property的变体:
<select v-selected="valOrObjectWithoutNesting">
// Now this code:
vnode.context.$data[binding.expression] = select.val();
// Equals to:
vnode.context.$data['valOrObjectWithoutNesting'] = select.val();
变体与第4级$ data&#39; s-property:
<select v-selected="objLvl1.objLvl2.objLvl3.objField">
// Now this code:
vnode.context.$data[binding.expression] = select.val();
// Equals to:
vnode.context.$data['objLvl1.objLvl2.objLvl3.objField'] = select.val(); // error here
所以我上面代码中的deepSet
函数&#34;转换&#34; $data['objLvl1.objLvl2.objLvl3.objField']
至$data['objLvl1']['objLvl2']['objLvl3']['objField']
。
正如您所看到的,正如我在您的问题的评论中提到的,当您希望使select2-wrapper更具可定制性时,指令方式比单独的组件方式复杂得多。在组件中,您可以根据需要传递尽可能多的配置道具和事件订阅,您可以避免执行像vnode.context.$data[binding.expression]
这样的侧面突变,并且您的代码将变得更容易理解并且更易于进一步支持。
答案 1 :(得分:0)
自定义指令完全没问题,除了使用inserted
挂钩而不是bind
。改编自Vue Wrapper Component Example。
要绑定到对象属性,最简单的方法是将其包装在计算的setter Computed Setter中并绑定到该属性。
注意,“深度设置”似乎不起作用。问题是变化检测之一,计算的设定器克服了这一点。 (注意on('change'
函数是jQuery而不是Vue。)
console.clear()
Vue.directive('selected', {
inserted: function (el, binding, vnode) {
var select = $(el);
select
.select2()
.val(binding.value)
.trigger('change')
.on('change', function () {
if (vnode.context[binding.expression]) {
vnode.context[binding.expression] = select.val();
}
})
},
});
var vm = new Vue({
el: '#my-app',
computed: {
selectedValue: {
get: function() { return this.myObj.type },
set: function (value) { this.myObj.type = value }
}
},
data: {
selectedVal: 0,
myObj: { type: 3 },
opts: [{
id: 1,
text: 'Test 1'
}, {
id: 2,
text: 'Test 2'
}, {
id: 3,
text: 'Test 3'
}]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/js/select2.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.4/vue.js"></script>
<div id="my-app">
<div>
<label for="example">Test dropdown list ({{ myObj.type }})</label>
</div>
<div>
<select id="example" style="width: 300px" v-selected="selectedValue">
<option v-for="(opt,index) in opts" :value="opt.id" :key="index">
{{ opt.text }}
</option>
</select>
</div>
</div>