91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

vue elementui 實現搜索欄公共組件封裝的實例代碼

發布時間:2020-09-30 10:58:30 來源:腳本之家 閱讀:1660 作者:醉逍遙neo 欄目:web開發

1、背景

vue后臺管理系統,會有很多表格頁面,表格上方會有一些搜索選項,表格直接使用el-table即可,而搜索欄區域每次寫起來都很繁瑣,而且多人開發情況下每個人寫的樣式都不相同,布局樣式無法統一。

所以要考慮對搜索欄做一個封裝,統一配置引用,提升開發維護效率和界面統一。

完成后的效果大概就是長這樣:

vue elementui 實現搜索欄公共組件封裝的實例代碼

2、分析

項目使用的是elementui框架,搜索欄這種表單提交,首先要使用el-form組件來封裝,而復雜點就是表單項可能有很多種,例如input輸入框、select選擇框、日期時間選擇框、日期時間范圍選擇框、cascader級聯選擇框等,每一項的字段名prop、名稱label、綁定的屬性方法都不盡相同。所以不能通過普通的綁定個別屬性的方式來處理,而slot插槽的方式也無法簡化,最終決定通過傳遞一個配置項數組的形式來解析生成相應的結構。

3、實現

目前實現的方式由兩部分組成,一部分是form表單組件,接受父組件傳遞的配置項數組,一部分是封裝一些常用的表單項組件,通過v-if來控制,form表單組件里引入該表單項組件,循環遍歷,根據傳遞的表單項類型來匹配顯示具體的表單項。

form表單組件(searchForm.vue)示例代碼:

<el-form
 :model="formData"
 ref="formRef"
 :inline="true"
>
 <el-form-item
 v-for="(item, index) in formOptions"
 :key="newKeys[index]"
 :prop="item.prop"
 :label="item.label ? (item.label + ':') : ''"
 :rules="item.rules"
 >
 <formItem
  v-model="formData[item.prop]"
  :itemOptions="item"
 />
 </el-form-item>
</el-form>

formItem表單項組件(formItem.vue)示例代碼:

<el-input
 v-if="isInput"
 v-model="currentVal"
 v-bind="bindProps"
 v-on="bindEvents"
 size="mini"
></el-input>

<el-select
 v-if="isSelect"
 v-model="currentVal"
 v-bind="bindProps"
 v-on="bindEvents"
 size="mini"
 clearable
 >
 <el-option
 v-for="item in itemOptions.options"
 :key="item.value"
 :label="item.label"
 :value="item.value"
 ></el-option>
</el-select>

4、關鍵點

由于elementui表單組件本身有很多配置屬性,不可能把所有的屬性和方法都寫死封裝,要想無縫支持,需要用到vue的v-bind和v-on特性,vue的v-bind和v-on支持賦值為對象類型,vue會自動遍歷對象里的屬性依次綁定,v2.4.0+支持。

5、參數配置項解釋

(1)示例:

[{
 label: '用戶名', // label文字
 prop: 'username', // 字段名
 element: 'el-input', // 指定elementui組件
 initValue: '阿黃', // 字段初始值
 placeholder: '請輸入用戶名', // elementui組件屬性
 rules: [{ required: true, message: '必填項', trigger: 'blur' }], // elementui組件屬性
 events: { // elementui組件方法
 input (val) {
 console.log(val)
 },
 }
}]

label 用于綁定給el-form-item上的label,表單項標題
prop 用于綁定給el-form-item上的prop,字段名,必填
element 指定elementui表單項的組件名,必填
initValue 表單項的初始值,可選
events 對象,對象里加方法,js原生方法或者elementui表單項組件支持的方法都可以加進去,通過v-on遍歷綁定
… 其他elementui表單項組件支持的屬性或者html原生屬性都可以添加,常用的例如rules表單校驗、placeholder提示,通過v-bind遍歷綁定

(2)參數傳遞解析的流程:

首先,searchForm.vue組件里通過props接收參數:

formOptions: {
 type: Array,
 required: true,
 default () {
 return []
 }
},

created組件里處理初始值:

// 添加初始值
addInitValue () {
 const obj = {}
 this.formOptions.forEach(v => {
 if (v.initValue !== undefined) {
  obj[v.prop] = v.initValue
 }
 })
 this.formData = obj
}

一部分配置項綁定在el-form-item上,一部分傳遞給formItem表單項組件再綁定:

<el-form-item
 v-for="(item, index) in formOptions"
 :key="newKeys[index]"
 :prop="item.prop"
 :label="item.label ? (item.label + ':') : ''"
 :rules="item.rules"
>
 <formItem
 v-model="formData[item.prop]"
 :itemOptions="item"
 />
</el-form-item>

formItem.vue表單項組件里props接受傳參:

itemOptions: {
 type: Object,
 default () {
 return {}
 }
}

computed里處理接收的參數itemOptions,生成要綁定的所有屬性對象bindProps:

// 綁定屬性
bindProps () {
 let obj = { ...this.itemOptions }
 // 移除已使用的或不相關的冗余屬性
 delete obj.label
 delete obj.prop
 delete obj.element
 delete obj.initValue
 delete obj.rules
 delete obj.events
 if (obj.element === 'el-select') {
 delete obj.options
 }
 return obj
},

computed里生成要綁定的所有方法對象bindEvents:

// 綁定方法
bindEvents () {
 return this.itemOptions.events || {}
},

最后dom里使用這些數據綁定:

<el-input
 v-if="isInput"
 v-model="currentVal"
 v-bind="bindProps"
 v-on="bindEvents"
></el-input>

(3)特殊情況的處理

由于elementui的el-select里是通過el-option遍歷實現的,而遍歷數組options按elementui官方不是綁定在el-select上的,所以針對el-select的配置項再加一個options里屬性,即select選擇項的數據數組。

<el-select
 v-if="isSelect"
 v-model="currentVal"
 v-bind="bindProps"
 v-on="bindEvents"
 size="mini"
 clearable
>
 <el-option
 v-for="item in itemOptions.options"
 :key="item.value"
 :label="item.label"
 :value="item.value"
 ></el-option>
</el-select>

elementui的日期時間選擇器分了很多種,根據業務需要分別處理一下,我這里是根據type劃分成了三種分開處理,最常用的是datetimerange日期時間范圍選擇器,作為默認項,還有一種monthrange,其余的都劃為一種。(具體處理見文章末尾的完整代碼)

6、按鈕組

按鈕其實就那么幾個,沒必要做太多的封裝,根據業務有哪些按鈕就封裝進去,目前我這里就封裝了三個按鈕。
通過props接受一個字符串標識按鈕組:

// 提交按鈕項,多個用逗號分隔(query搜索, export導出, reset重置)
btnItems: {
 type: String,
 default () {
 return 'search'
 }
}

7、使用方式示例

dom:

<!-- 搜索 -->
<searchForm :formOptions="formOptions" @onSearch="onSearch"/>

vue data里:

formOptions: [
 {
 label: '意見內容',
 prop: 'content',
 element: 'el-input'
 },
 {
 label: '類型',
 prop: 'type',
 element: 'el-select',
 options: [
  { label: '給點意見', value: '1' },
  { label: '售后問題', value: '2' }
 ]
 },
 {
 label: '狀態',
 prop: 'status',
 element: 'el-select',
 options: getFeedbackStatus()
 },
 {
 label: '提交時間',
 prop: 'timeRange',
 element: 'el-date-picker'
 }
],

vue methods里:

// 獲取搜索表單提交的數據
onSearch (val) {
 console.log(val)
}

8、完整代碼

(1)searchForm.vue

/**
 * Created by hanxueqiang on 200107
 *
 * 搜索欄公共組件
 */
<template>
 <div class="search-form-box">
 <el-form
  :model="formData"
  ref="formRef"
  :inline="true"
 >
  <el-form-item
  v-for="(item, index) in formOptions"
  :key="newKeys[index]"
  :prop="item.prop"
  :label="item.label ? (item.label + ':') : ''"
  :rules="item.rules"
  >
  <formItem
   v-model="formData[item.prop]"
   :itemOptions="item"
  />
  </el-form-item>
 </el-form>

 <!-- 提交按鈕 -->
 <div class="btn-box">
  <el-button
  v-if="btnItems.includes('search')"
  size="mini"
  type="primary"
  class="btn-search"
  @click="onSearch"
  >搜索</el-button>

  <el-button
  v-if="btnItems.includes('export')"
  size="mini"
  type="primary"
  class="btn-export"
  @click="onExport"
  >導出</el-button>

  <el-button
  v-if="btnItems.includes('reset')"
  size="mini"
  type="default"
  class="btn-reset"
  @click="onReset"
  >重置</el-button>
 </div>
 </div>
</template>

<script>
import formItem from './formItem'
import tools from '@/utils/tools'

export default {
 props: {
 /**
  * 表單配置
  * 示例:
  * [{
  * label: '用戶名', // label文字
  * prop: 'username', // 字段名
  * element: 'el-input', // 指定elementui組件
  * initValue: '阿黃', // 字段初始值
  * placeholder: '請輸入用戶名', // elementui組件屬性
  * rules: [{ required: true, message: '必填項', trigger: 'blur' }], // elementui組件屬性
  * events: { // elementui組件方法
  *  input (val) {
  *  console.log(val)
  *  },
  *  ...... // 可添加任意elementui組件支持的方法
  * }
  * ...... // 可添加任意elementui組件支持的屬性
  * }]
  */
 formOptions: {
  type: Array,
  required: true,
  default () {
  return []
  }
 },
 // 提交按鈕項,多個用逗號分隔(query, export, reset)
 btnItems: {
  type: String,
  default () {
  return 'search'
  }
 }
 },

 data () {
 return {
  formData: {}
 }
 },

 computed: {
 newKeys () {
  return this.formOptions.map(v => {
  return tools.createUniqueString()
  })
 }
 },

 created () {
 this.addInitValue()
 },

 methods: {
 // 校驗
 onValidate (callback) {
  this.$refs.formRef.validate(valid => {
  if (valid) {
   console.log('提交成功')
   console.log(this.formData)
   callback()
  }
  })
 },
 // 搜索
 onSearch () {
  this.onValidate(() => {
  this.$emit('onSearch', this.formData)
  })
 },
 // 導出
 onExport () {
  this.onValidate(() => {
  this.$emit('onExport', this.formData)
  })
 },
 onReset () {
  this.$refs.formRef.resetFields()
 },
 // 添加初始值
 addInitValue () {
  const obj = {}
  this.formOptions.forEach(v => {
  if (v.initValue !== undefined) {
   obj[v.prop] = v.initValue
  }
  })
  this.formData = obj
 }
 },

 components: { formItem }
}
</script>

<style lang='less' scoped>
.search-form-box {
 display: flex;
 margin-bottom: 15px;

 .btn-box {
 padding-top: 5px;
 display: flex;

 button {
  height: 28px;
 }
 }
 .el-form {
 /deep/ .el-form-item__label {
  padding-right: 0;
 }
 .el-form-item {
  margin-bottom: 0;

  &.is-error {
  margin-bottom: 22px;
  }
 }
 // el-input寬度
 /deep/ .form-item {
  > .el-input:not(.el-date-editor) {
  width: 120px;
  }
 }
 /deep/ .el-select {
  width: 120px;
 }
 /deep/ .el-cascader {
  width: 200px;
 }
 }
}

</style>

(2)formItem.vue

/**
 * Created by hanxueqiang on 200107
 *
 * 表單匹配項
 */
<template>
 <div class='form-item'>
 <el-input
  v-if="isInput"
  v-model="currentVal"
  v-bind="bindProps"
  v-on="bindEvents"
  size="mini"
 ></el-input>

 <el-input-number
  v-if="isInputNumber"
  v-model="currentVal"
  v-bind="bindProps"
  v-on="bindEvents"
  :controls-position="itemOptions['controls-position'] || 'right'"
  size="mini"
 ></el-input-number>

 <el-select
  v-if="isSelect"
  v-model="currentVal"
  v-bind="bindProps"
  v-on="bindEvents"
  size="mini"
  clearable
  >
  <el-option
  v-for="item in itemOptions.options"
  :key="item.value"
  :label="item.label"
  :value="item.value"
  ></el-option>
 </el-select>

 <!-- datetimerange/daterange -->
 <el-date-picker
  v-if="isDatePickerDateRange"
  v-model="currentVal"
  v-bind="bindProps"
  v-on="bindEvents"
  :type="itemOptions.type || 'datetimerange'"
  size="mini"
  clearable
  :picker-options="pickerOptionsRange"
  start-placeholder="開始日期"
  range-separator="至"
  end-placeholder="結束日期"
  :default-time="['00:00:00', '23:59:59']"
  value-format="yyyy-MM-dd HH:mm:ss"
 ></el-date-picker>

 <!-- monthrange -->
 <el-date-picker
  v-if="isDatePickerMonthRange"
  v-model="currentVal"
  v-bind="bindProps"
  v-on="bindEvents"
  type="monthrange"
  size="mini"
  clearable
  :picker-options="pickerOptionsRangeMonth"
  start-placeholder="開始日期"
  range-separator="至"
  end-placeholder="結束日期"
  value-format="yyyy-MM"
 ></el-date-picker>

 <!-- others -->
 <el-date-picker
  v-if="isDatePickerOthers"
  v-model="currentVal"
  v-bind="bindProps"
  v-on="bindEvents"
  :type="itemOptions.type"
  size="mini"
  clearable
  placeholder="請選擇日期"
 ></el-date-picker>

 <el-cascader
  v-if="isCascader"
  v-model="currentVal"
  v-bind="bindProps"
  v-on="bindEvents"
  size="mini"
  clearable
 ></el-cascader>
 </div>
</template>

<script>
import tools from '@/utils/tools'

export default {
 inheritAttrs: false,

 props: {
 value: {},
 itemOptions: {
  type: Object,
  default () {
  return {}
  }
 }
 },

 data () {
 return {
  pickerOptionsRange: tools.pickerOptionsRange,
  pickerOptionsRangeMonth: tools.pickerOptionsRangeMonth
 }
 },

 computed: {
 // 雙向綁定數據值
 currentVal: {
  get () {
  return this.value
  },
  set (val) {
  this.$emit('input', val)
  }
 },
 // 綁定屬性
 bindProps () {
  let obj = { ...this.itemOptions }
  // 移除冗余屬性
  delete obj.label
  delete obj.prop
  delete obj.element
  delete obj.initValue
  delete obj.rules
  delete obj.events
  if (obj.element === 'el-select') {
  delete obj.options
  }
  return obj
 },
 // 綁定方法
 bindEvents () {
  return this.itemOptions.events || {}
 },
 // el-input
 isInput () {
  return this.itemOptions.element === 'el-input'
 },
 // el-input-number
 isInputNumber () {
  return this.itemOptions.element === 'el-input-number'
 },
 // el-select
 isSelect () {
  return this.itemOptions.element === 'el-select'
 },
 // el-date-picker (type: datetimerange/daterange)
 isDatePickerDateRange () {
  const isDatePicker = this.itemOptions.element === 'el-date-picker'
  const isDateRange = !this.itemOptions.type ||
  this.itemOptions.type === 'datetimerange' ||
  this.itemOptions.type === 'daterange'
  return isDatePicker && isDateRange
 },
 // el-date-picker (type: monthrange)
 isDatePickerMonthRange () {
  const isDatePicker = this.itemOptions.element === 'el-date-picker'
  const isMonthRange = this.itemOptions.type === 'monthrange'
  return isDatePicker && isMonthRange
 },
 // el-date-picker (type: other)
 isDatePickerOthers () {
  const isDatePicker = this.itemOptions.element === 'el-date-picker'
  return isDatePicker && !this.isDatePickerDateRange && !this.isDatePickerMonthRange
 },
 // el-cascader
 isCascader () {
  return this.itemOptions.element === 'el-cascader'
 }
 },

 created () {},

 methods: {},

 components: {}
}
</script>

<style lang='less' scoped>

</style>

(3)依賴引入的一些函數方法 tools.js

/**
 * 創建唯一的字符串
 * @return {string} ojgdvbvaua40
 */
function createUniqueString () {
 const timestamp = +new Date() + ''
 const randomNum = parseInt((1 + Math.random()) * 65536) + ''
 return (+(randomNum + timestamp)).toString(32)
}

// elementui日期時間范圍 快捷選項
const pickerOptionsRange = {
 shortcuts: [
 {
  text: '今天',
  onClick (picker) {
  const end = new Date()
  const start = new Date(new Date().toDateString())
  start.setTime(start.getTime())
  picker.$emit('pick', [start, end])
  }
 }, {
  text: '最近一周',
  onClick (picker) {
  const end = new Date()
  const start = new Date()
  start.setTime(end.getTime() - 3600 * 1000 * 24 * 7)
  picker.$emit('pick', [start, end])
  }
 }, {
  text: '最近一個月',
  onClick (picker) {
  const end = new Date()
  const start = new Date()
  start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
  picker.$emit('pick', [start, end])
  }
 }, {
  text: '最近三個月',
  onClick (picker) {
  const end = new Date()
  const start = new Date()
  start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
  picker.$emit('pick', [start, end])
  }
 }
 ]
}

// elementui月份范圍 快捷選項
const pickerOptionsRangeMonth = {
 shortcuts: [
 {
  text: '今年至今',
  onClick (picker) {
  const end = new Date()
  const start = new Date(new Date().getFullYear(), 0)
  picker.$emit('pick', [start, end])
  }
 },
 {
  text: '最近半年',
  onClick (picker) {
  const end = new Date()
  const start = new Date()
  start.setMonth(start.getMonth() - 6)
  picker.$emit('pick', [start, end])
  }
 },
 {
  text: '最近一年',
  onClick (picker) {
  const end = new Date()
  const start = new Date()
  start.setMonth(start.getMonth() - 12)
  picker.$emit('pick', [start, end])
  }
 }
 ]
}

(4)一些elmentui全局樣式的修改

// el-input-number (controls-position="right")
.el-input-number.is-controls-right {
 .el-input-number__decrease {
 display: none;
 }
 .el-input-number__increase {
 display: none;
 top: 2px; // fix style bug
 }
 &:hover {
 .el-input-number__decrease {
  display: inline-block;
 }
 .el-input-number__increase {
  display: inline-block;
 }
 }
 .el-input__inner {
 text-align: left;
 padding-left: 5px;
 padding-right: 40px;
 }
}

// el-date-picker datetimerange
.el-date-editor.el-date-editor--datetimerange {
 .el-range-separator {
 width: 24px;
 color: #999;
 padding: 0;
 }
 .el-range__icon {
 margin-left: 0;
 }
 &.el-input__inner {
 vertical-align: middle;
 padding: 3px 5px;
 }
 &.el-range-editor--medium {
 width: 380px;

 .el-range-separator {
  line-height: 30px;
 }
 }
 &.el-range-editor--mini {
 width: 330px;

 .el-range-separator {
  line-height: 22px;
 }
 }
}

// el-date-picker not datetimerange
.el-date-editor {
 .el-input__prefix {
 left: 0;
 top: 1px;
 }
 .el-input__suffix {
 right: 0;
 top: 1px;
 }
 .el-input__inner {
 padding: 0 25px;
 }
 &.el-input--mini {
 width: 175px;
 }
 &.el-input--medium {
 width: 195px;
 }
}

// input padding
.el-input__inner {
 padding: 0 5px;
}

總結

以上所述是小編給大家介紹的vue elementui 實現搜索欄公共組件封裝,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!

如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

伊春市| 双辽市| 涞源县| 绵阳市| 成都市| 遂平县| 缙云县| 治多县| 福建省| 壶关县| 长宁县| 涞水县| 万年县| 张北县| 宁阳县| 马山县| 勐海县| 台湾省| 宝坻区| 涿州市| 东光县| 沁水县| 西城区| 清河县| 迭部县| 奎屯市| 永仁县| 宁陵县| 尤溪县| 沛县| 麦盖提县| 左权县| 万宁市| 涿州市| 海南省| 侯马市| 保山市| 上栗县| 沾益县| 景宁| 封丘县|