相信使用過elementui的同窗確定也使用過Select選擇器組件,同時也確定使用過其遠程搜索模式。在開啓遠程搜索後,能夠根據輸入的關鍵字去後端獲取列表,而後進行選擇。本文說的下拉組件其實也是elementui的Select選擇器組件,不過會對其進一步封裝,以方便業務系統使用。前端
咱們先簡單分析一下下拉組件應該具有的功能:vue
使用到下拉組件的狀況通常是須要選擇的數據來源於另外一個接口,好比添加用戶的時候,須要選擇角色。此時數據源就來自角色列表接口。這裏簡單講一下可能存在的狀況:git
修改模式的場景算是一種比較特殊的場景,須要進行以下處理:json
爲了儘量的複用接口,這裏依然使用的是後端默認查詢的列表接口如:sys/role/list
、sys/user/user
等。下面以用戶列表爲例:後端
請求地址api
{{api_base_url}}/sys/user/user
bash
數據類型app
application/json
框架
請求示例:異步
選擇單條記錄
{
"m_LIKE_userName",""
}
====>由src/utils.request.js全局請求數據處理進行轉換
{
"whereParams": [{
"operateType": "LIKE",
"propertyName": "userName",
"propertyValue": ""
}]
}
複製代碼
修改模式下選擇單條記錄,每次查詢都要返回當前id的記錄
{
"m_LIKE_userName","",
"mor_EQ_id": 1
}
====>由src/utils.request.js全局請求數據處理進行轉換
{
"whereParams": [{
"operateType": "LIKE",
"propertyName": "userName",
"propertyValue": ""
}, {
"operateType": "OR",
"propertyName": "id",
"propertyValue": {
"operateType": "EQ",
"propertyName": "id",
"propertyValue": 1
}
}]
}
複製代碼
選擇多條記錄
{
"m_LIKE_userName",""
}
====>由src/utils.request.js全局請求數據處理進行轉換
{
"whereParams": [{
"operateType": "LIKE",
"propertyName": "userName",
"propertyValue": ""
}]
}
複製代碼
修改模式下選擇多條記錄,每次查詢都要返回當前id的記錄
{
"m_LIKE_userName","",
"mor_EQ_id": [1, 2]
}
====>由src/utils.request.js全局請求數據處理進行轉換
{
"whereParams": [{
"operateType": "LIKE",
"propertyName": "userName",
"propertyValue": ""
}, {
"operateType": "OR",
"propertyName": "id",
"propertyValue": {
"operateType": "EQ",
"propertyName": "id",
"propertyValue": [1,2]
}
}]
}
複製代碼
響應示例:
{
"code": 0,
"msg": "查詢用戶成功",
"data": {
"pageNum": 1,
"pageSize": 15,
"recordCount": 4,
"totalPage": 1,
"rows": [{
"id": 1,
"userName": "admin",
"realName": "mldong",
"avatar": "",
"email": "",
"mobilePhone": "18676163666",
"telephone": "",
"password": "52618c88aa68c63d37e50d6acd8b8456",
"salt": "v7hc7v69",
"sex": 1,
"isLocked": 1,
"createTime": "2020-06-09 21:47:33",
"updateTime": "2020-06-24 10:11:03",
"isDeleted": 1
}, {
"id": 9,
"userName": "ni",
"realName": "大的",
"email": "8551312@163.com",
"mobilePhone": "13023123256",
"password": "c079872794690156289617a60a11c316",
"salt": "ztih3jzc",
"sex": 2,
"isLocked": 1,
"createTime": "2020-06-22 10:01:12",
"updateTime": "2020-06-22 10:04:46",
"isDeleted": 1
}, {
"id": 10,
"userName": "地方v的",
"realName": "hghg",
"email": "13696452586@163.com",
"mobilePhone": "13645607895",
"password": "d9acbc2eef540ffc8ea6dd8fdacd37cc",
"salt": "jpqocubh",
"sex": 2,
"isLocked": 1,
"createTime": "2020-06-22 10:06:41",
"updateTime": "2020-06-22 10:06:41",
"isDeleted": 1
}, {
"id": 11,
"userName": "孫狗",
"realName": "孫笑川",
"mobilePhone": "17444444444",
"password": "7941882c9fdcd4bb2a17b804d2b5c5ba",
"salt": "ewst066f",
"sex": 1,
"isLocked": 1,
"createTime": "2020-06-22 15:03:06",
"updateTime": "2020-06-22 15:03:06",
"isDeleted": 1
}]
}
}
複製代碼
暫時定幾個經常使用的參數,後續可能還會有追加
參數名 | 類型 | 默認值 | 說明 |
---|---|---|---|
valueKey | String | id | 列表中選項的值對應的key |
labelKey | String | name | 列表中選項的值對應的key |
searchKey | String | name | 模糊搜索的key |
url | String | undefined | 接口地址 |
isEdit | Boolean | false | 是否編輯模式 |
value | String, Number, Array | undefined | 綁定的值 |
multiple | Boolean | false | 是否多選 |
size | String | medium | 組件大小medium/small/mini |
placeholder | String | 請選擇 | 佔位符 |
├── src
├── components/m
├── Select
└── index.vue
├── utils
└── request.js
├── views
├── dashboard
└── index.vue
└── main.js
複製代碼
src/components/m/Select/index.vue
下拉組件
<template>
<div class="m-select">
<!--el-input readonly :size="size" :placeholder="placeholder" v-model="mValue">
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input-->
<el-select
:size="size"
filterable
:multiple="multiple"
remote
:loading="loading"
:remote-method="requestData"
:placeholder="placeholder"
@change="handleChange"
v-model="mValue">
<el-option
v-for="item in options"
:key="item[valueKey]"
:label="item[labelKey]"
:value="item[valueKey]">
<slot v-bind:option="item"> </slot>
</el-option>
</el-select>
</div>
</template>
<script>
import request from '@/utils/request'
export default {
name: 'MSelect',
props: {
valueKey: { // 列表中選項的值對應的key
type: String,
default: 'id'
},
labelKey: { // 列表中選項的標籤對應的key
type: String,
default: 'name'
},
searchKey: { // 模糊搜索的key
type: String,
default: 'name'
},
url: { // 接口地址
type: String,
default: undefined
},
isEdit: { // 是否編輯模式
type: Boolean,
default: false
},
// 綁定的值
value: {
type: [String, Number, Array],
default: undefined
},
multiple: { // 是否多選
type: Boolean,
default: false
},
size: { // medium/small/mini
type: String,
default: 'medium'
},
placeholder: { // 佔位符
type: String,
default: '請選擇'
}
},
data() {
return {
loading: false,
mValue: undefined,
options: []
}
},
watch: {
value(n, o) { // 監聽父組件值變更,子組件也要變更
this.mValue = n
if ((o === undefined && this.isEdit) || (o !== undefined && o.length === 0 && this.isEdit)) {
// 若是舊的值等於undefined
this.requestData('')
}
}
},
created() {
if (!this.isEdit) {
this.requestData('')
}
},
methods: {
// 請求數據
requestData(k) {
if (this.url) {
this.loading = true
var operateType = this.multiple ? 'IN' : 'EQ'
request({
url: this.url,
method: 'post',
data: {
['m_LIKE_' + this.searchKey]: k,
[`mor_${operateType}_` + this.valueKey]: this.value
}
}).then(res => {
this.loading = false
if (res.code === 0) {
this.options = res.data.rows
}
}).catch(() => {
this.loading = false
})
}
},
// 子組件值變化要經過父組件
handleChange(value) {
this.$emit('input', value)
}
}
}
</script>
複製代碼
src/utils/request.js
新增or的全局處理,代碼片斷
// request interceptor
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// 存在token,就放到請求頭中
// 這裏修改一下請求頭與後端一致,X-Token->Auth-Token
config.headers['Auth-Token'] = getToken()
}
if (config.data) {
// 這裏對全局的請求參數作處理,主要是拼接查詢條件
var whereParams = []
Object.keys(config.data).forEach(item => {
if (item.startsWith('m_')) {
var value = config.data[item]
if (value !== undefined) {
var arr = item.split('_')
if (arr.length === 3) {
whereParams.push({
operateType: arr[1],
propertyName: arr[2],
propertyValue: value
})
}
}
delete config.data[item]
} else if (item.startsWith('mor_')) {
// 處理簡單的or語句
value = config.data[item]
arr = item.split('_')
if (value !== undefined) {
if (arr.length === 3) {
whereParams.push({
operateType: 'OR',
propertyName: arr[2],
propertyValue: {
operateType: arr[1],
propertyName: arr[2],
propertyValue: value
}
})
}
}
delete config.data[item]
}
})
if (whereParams.length) {
config.data.whereParams = whereParams
}
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
複製代碼
src/main.js
主入口全局註冊自定義組件,這裏也用了require.context,代碼片斷
import Vue from 'vue'
// 處理自定義組件全局註冊
const files = require.context('./components/m', true, /\.vue$/)
files.keys().forEach((routerPath) => {
const componentName = routerPath.replace(/^\.\/(.*)\/index\.\w+$/, '$1')
const value = files(routerPath)
Vue.component('m-' + componentName.toLowerCase(), value.default)
}, {})
複製代碼
src/views/dashboard/index.vue
這裏提供了使用樣例:
選擇單個
<m-select v-model="userId" url="sys/user/list" value-key="id" label-key="userName" search-key="userName"></m-select>
複製代碼
選擇單個-修改模式
<m-select is-edit v-model="form.userId" url="sys/user/list" value-key="id" label-key="userName" search-key="userName"></m-select>
複製代碼
選擇多個
<m-select multiple v-model="userIds" url="sys/user/list" value-key="id" label-key="userName" search-key="userName"></m-select>
複製代碼
選擇多個-修改模式
<m-select multiple is-edit v-model="form.userIds" url="sys/user/list" value-key="id" label-key="userName" search-key="userName"></m-select>
複製代碼
自定義佈局
<m-select v-model="userId" url="sys/user/list" value-key="id" label-key="userName" search-key="userName">
<template v-slot:default="{ option }">
<span>{{ option.id }}--{{ option.userName }}</span>
</template>
</m-select>
複製代碼
js片斷
export default {
name: 'Dashboard',
data() {
return {
form: {
userId: undefined,
userIds: []
},
userId: undefined,
userIds: []
}
},
created() {
// 模擬修改異步更新
setTimeout(() => {
this.$set(this.form, 'userId', 1)
this.$set(this.form, 'userIds', [1, 9])
}, 2000)
}
}
複製代碼
本文的下拉組件仍是很粗淺的封裝,目前的交互也是根據本身的操做習慣去作的,除了該種作法外,還有一種作法是彈出框的方式,後續作到下拉菜單樹的時候會考慮使用該種方式。