“正儿八经”的做一个让semantic下拉菜单更支持vue的组件(上)
本文将分两部分,上篇主要描述组件功能的开发,下篇将描述打包发布
首先给大家拜个早年。。。没想到距离上一篇竟然隔了那么久,中间发生了一些事吧。。。现在整个人应该成熟了些,社会啊
转入正题,近两年是各种mvvm框架发展的鼎盛时期啊,公司也一直在努力,终于在几个月前逐渐全员切换到了vue
然额,人生总是不能随你所欲,技术是切换了,但在UI框架上仍然使用着普通框架,比如semantic。
我不是针对谁,其他人虽然没啥感觉,但对于玩过了vuetify, mint-ui等我来说,在一个可以数据双向绑定的地方强迫被使用semantic的数据交互方式,这是何等的**啊。。而且前后端还没分离,没分离,没分离。。。
好在这是一个月前的事了,现在我的建(强)议(迫)下,我们进行了重构分离了前后端并开始使用element-ui(跪谢饿了么前端大佬们)
正文
咳,感觉说了很多废话。其实这个小项目早在两个月前就写好了发到git上了,迫于各种因素(懒)一直没有好好写一个笔记记录,现在好像忘的差不多了。。。README.md还是有好好写的,可以到git看:vue-semantic-dropdown
当时使用semantic做一些下拉菜单的需求,经常会有级联选择的那种,一来来三个,本来可以用v-modal分分钟搞定的,但奈何semantic的下拉菜单结构都是这样的1
2
3
4
5
6
7
8
9<div class="ui selection dropdown">
<input type="hidden" name="gender">
<i class="dropdown icon"></i>
<div class="default text">Gender</div>
<div class="menu">
<div class="item" data-value="1">Male</div>
<div class="item" data-value="0">Female</div>
</div>
</div>
你说我绑哪!绑最外层div肯定不对,看它交互是吧选中value放input里的,但绑在一个hidden的input也不管用啊,一个级联愣是写了几十行。。。
通过查阅资料,我发现可以这样手动设置<input type="hidden" v-model="value">
thenthis.$emit('input', theValue)
把它封在组件内部,在外面引用的也可以把这坨当成一个普通的input使用v-model进行操作,因垂死庭
查资料的时候发现遇到这个问题的小伙伴还不少,如果我把它开源了,是不是就能帮助到别人,至少是公司的小伙伴?兴奋~
say do let’s do, 先看下都有哪些需要设置成可配置的:
class
不同的风格可能有不同需求,name
在表单里可能会用到default text
默认显示的文本options
下拉菜单的主要数据list,每项包含value和text
ok:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40<template>
<div :class="classList">
<input type="hidden" :name="name" v-model="value">
<i class="dropdown icon"></i>
<div class="default text">{{ defaultText }}</div>
<div class="menu">
<div class="item" v-for="(option, index) in list" :key="index"
:data-value="option.value" :data-text="option.text"
>{{ option.text }}</div>
</div>
</div>
</template>
<script>
export default {
props: {
addClass: {
type: String
},
name: {
type: String,
required: true
},
value: {
required: true
},
defaultText: {
required: true
},
options: {
required: true
},
},
computed: {
classList: function() {
return 'ui dropdown ' + this.addClass;
},
}
</script>
然后是数据处理1
2
3
4
5
6
7
8
9
10
11
12
13methods: {
initDropdown: function() {
var self = this,
settings = {
action: 'activate',
onChange: function(value, text){
self.$emit('input', value)
}
}
$(this.$el).dropdown(settings)
}
}
然后再把这个函数放到mounted()里,是不是超简单。不过既然要给别人用,还是要尽量满足多样化的需求,比如人家的action
不是activate
啦;人家的option的key叫id和text啦;dropdown()里有其他的操作啦
最后经过优化1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103<template>
<div :class="classList">
<input type="hidden" :name="name" v-model="value">
<i class="dropdown icon"></i>
<div class="default text">{{ defaultText }}</div>
<div class="menu">
<div class="item" v-for="(option, index) in list" :key="index"
:data-value="option.value" :data-text="option.text"
>{{ option.text }}</div>
</div>
</div>
</template>
<script>
export default {
props: {
addClass: {
type: String
},
name: {
type: String,
required: true
},
value: {
required: true
},
defaultText: {
required: true
},
options: {
required: true
},
textFiled: {
default: 'text'
},
valueFiled: {
default: 'value'
},
action: {
type: String,
default: 'activate'
},
setting: {
type: Object
}
},
mounted() {
this.$nextTick(() => {
this.initDropdown()
})
},
updated() {
this.$nextTick(() => {
this.initDropdown()
})
},
computed: {
classList: function() {
return 'ui dropdown ' + this.addClass;
},
list: function() {
if(!this.options) {
console.error('options is null')
}
return this.options.map((option) => {
if(option.constructor === Object) {
return {
text: option[this.textFiled],
value: option[this.valueFiled]
}
} else {
return {
text: option,
value: option
}
}
})
}
},
methods: {
initDropdown: function() {
var self = this,
settings = $.extend({
action: this.action,
onChange: function(value, text){
self.$emit('input', value)
// 传递选中的文本
self.$emit('dropdown-selected', text)
}
}, this.setting)
$(this.$el).dropdown(settings)
}
}
}
</script>
最后加上update()和this.$nextTick()双重保障以防value在刷新和重新渲染的时候出现异常
使用的时候import然后注册组件然后就可以这样使用咯1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25<Dropdown addClass="selection" name="selection" defaultText="请选择"
v-model="selectedValue" :options="options"
textFiled="value" valueFiled="id"
@dropdown-selected="(text) => { selectedText = text}"
></Dropdown>
<span>id: {{ selectedValue }} name:{{ selectedText }} </span>
...
data() {
return {
options: [
{
id: 'litteRed',
value: '小红'
},
{
id: 'litteBlue',
value: '小蓝'
}
],
selectedValue: null,
selectedText: null,
}
}
详细可以装一个看看咯,包里面有例子的咯,npm install vue-semantic-dropdown --save
求点赞哟