一、新建demo工程
vue init webpack-simple demo
添加src/mixins/emitter.js文件(見前幾篇博文)
安裝font-awesome字體庫:
cnpm install font-awesome --save
配置webpack.config.js,引入字體文件:
{ test: /\.(otf|eot|ttf|woff|woff2)$/, loader: 'file-loader' }
在src/main.js中引入font-awesome:
import '../node_modules/font-awesome/css/font-awesome.min.css'
二、組件設計
新建src/components/mySelect.vue和myOption.vue文件
1) 先來設計選項組件,這個比較簡單
先來考慮一下使用場景,一般的下拉菜單都是由無序列表組成,而選項則是一個個列表項:
但是直接slot標簽很可能會出現重名,所以需要分別prop一個label和value,其中value是必須的,如果沒有slot標簽則顯示label,所以myOption的基本結構為:
<template> <li class="my-option"> <span v-if="!$slots.default">{{ label }}</span> <slot></slot> </li> </template> <script> import emitter from "../mixins/emitter"; export default { name: "myOption", mixins: [emitter], props: { label: { type: String, default: "empty-label" }, value: { type: String, required: true } } }; </script>
然后來考慮一下myOption可能會存在的狀態,選項有選擇和取消兩種事件,對應的狀態就是是否已經被選擇,而且選擇的狀態需要高亮顯示:
先來加一個狀態:
data() { return { selected: true } }
然后在最外層的li添加一個selected類名和一個右浮的check圖標(可以用v-show="selected"來控制顯示,我這里用css與文字顏色一起控制):
<template> <li :class="['my-option', { selected: selected }]"> <span v-if="!$slots.default">{{ label ? label : value }}</span> <slot></slot> <i class="fa fa-check pull-right"> </i> </li> </template>
css代碼:
<style lang="scss" scoped> .my-option { > .fa-check { display: none; } &.selected { color: blue; > .fa-check { display: inline; } } } </style>
由於父組件select需要接收label的值,而prop不能改變,只好再定義一個myLabel標簽,然后通過事件發送給父級:
myLabel: this.label || this.value
先后添加點擊事件和監聽的選擇/取消事件:
methods: { handleClick() { this.dispatch( "mySelect", "option-click", this.selected, this.myLabel, this.value ); } }, created() { this.$on("select", value => { if (this.value === value) { this.selected = true; } }); this.$on("cancel", value => { if (this.value === value) { this.selected = false; } }); }
然后,不帶樣式的選項組件基本就完成了,完整代碼如下:
<template> <li :class="['my-option', { selected: selected }]"> <span v-if="!$slots.default">{{ myLabel }}</span> <slot></slot> <i class="fa fa-check pull-right"> </i> </li> </template> <script> import emitter from "../mixins/emitter"; export default { name: "myOption", mixins: [emitter], props: { label: { type: String, default: "" }, value: { type: String, required: true } }, data() { return { selected: false, myLabel: this.label || this.value }; }, methods: { handleClick() { this.dispatch( "mySelect", "option-click", this.selected, this.myLabel, this.value ); } }, created() { this.$on("select", value => { if (this.value === value) { this.selected = true; } }); this.$on("cancel", value => { if (this.value === value) { this.selected = false; } }); } }; </script> <style lang="scss" scoped> .my-option { > .fa-check { display: none; } &.selected { color: blue; > .fa-check { display: inline; } } } </style>