1.简述

element-ui是由饿了么前端团队推出的一套为开发者、设计师和产品经理准备的基于 vue 实现的一套不依赖业务的 UI 组件库,提供了丰富的PC端组件,减少用户对常用组件的封装,降低了开发的难易程度。而手机端有对应框架是 Mint UI

2.官方文档

https://element.eleme.cn/2.15/#/zh-CN/component/quickstart

3.TABLE自定义列筛选器

3.1.说明

element-ui默认的table组件支持的表头筛选器是比较简单的只支持数组的下拉单选或多选的形式,但有时候因为不同的需求不同的场景,需要支持输入框形式。

image.png

3.2.代码

  1. ////////////////////////////////////////header-tools///////////////////////////////////////
  2. <template>
  3. <el-popover :placement="placement" :width="width" v-model="visible">
  4. <div class="header-tools-order">
  5. <div @click="sortOrder('ascending')" class="order-item AZ-anime"><i class="el-icon-top"></i>升序</div>
  6. <div @click="sortOrder('descending')" class="order-item AZ-anime"><i class="el-icon-bottom"></i>降序</div>
  7. <div @click="sortOrder(null)" class="order-item AZ-anime"><i class="el-icon-close"></i>取消排序</div>
  8. </div>
  9. <h3 v-text="label"></h3>
  10. <div class="header-tools-body">
  11. <div>
  12. <el-select class="filter-mode-select" v-model="option.filterMode">
  13. <el-option v-for="operation in operationList" :key="operation.value" :value="operation.value" :label="operation.label"></el-option>
  14. </el-select>
  15. </div>
  16. <el-input v-if="['_null','_not_null','_in','_not_in'].indexOf(option.filterMode)<0" v-model="option.inputValue" clearable />
  17. <el-input v-if="['_between'].indexOf(option.filterMode)>-1" v-model="option.subInputValue" clearable />
  18. <div class="option-list-input container-flex-space-between" v-if="['_in','_not_in'].indexOf(option.filterMode)>-1" v-for="(op,opIndex) in option.optionList">
  19. <el-input v-model="op.inputValue" @paste.native.capture.prevent="onPaste($event,opIndex)" clearable />
  20. <div class="container-flex-space-between">
  21. <i @click="addFilter(opIndex)" class="el-icon-circle-plus"></i>
  22. <i v-if="option.optionList.length > 1" @click="removeFilter(opIndex)" class="el-icon-error"></i>
  23. </div>
  24. </div>
  25. </div>
  26. <div class="header-tools-footer container-flex-space-between">
  27. <el-button size="small" @click="visible = false">关闭</el-button>
  28. <el-button size="small" type="primary" @click="doSubmit()">确定</el-button>
  29. </div>
  30. <span slot="reference" class="header-tools-title">
  31. <span :class="{'has-search':hasFilter()}" :title="label" v-text="label"></span>
  32. <span style="white-space: nowrap;">
  33. <span class="caret-wrapper">
  34. <i class="sort-caret ascending"></i>
  35. <i class="sort-caret descending"></i>
  36. </span>
  37. <i class="fa fa-filter AZ-anime" :class="{'has-search':hasFilter()}"></i>
  38. </span>
  39. </span>
  40. </el-popover>
  41. </template>
  42. <script>
  43. export default {
  44. name: 'header-tools',
  45. props: {
  46. placement: {
  47. type: String,
  48. default: 'bottom'
  49. },
  50. width: {
  51. type: String,
  52. default: '240'
  53. },
  54. dataType: {
  55. type: String,
  56. default: 'string'
  57. },
  58. label: String,
  59. prop: String,
  60. mirrorProp: String //解决列的prop和headerTools的prop不一致导致不能排序问题
  61. },
  62. data () {
  63. return {
  64. visible: false,
  65. option:{
  66. inputValue:'',
  67. subInputValue:'',
  68. filterMode:'_eq',
  69. optionList:[{
  70. inputValue:''
  71. }]
  72. },
  73. operationList:[],
  74. stringOperation:[
  75. {value:'_eq',label:'正好是'},
  76. {value:'_ne',label:'不是'},
  77. {value:'_like',label:'包含'},
  78. {value:'_not_like',label:'不包含'},
  79. {value:'_in',label:'在之中'},
  80. {value:'_not_in',label:'不在之中'},
  81. {value:'_null',label:'为空'},
  82. {value:'_not_null',label:'不为空'}
  83. ],
  84. numberOperation:[
  85. {value:'_eq',label:'等于'},
  86. {value:'_ne',label:'不等于'},
  87. {value:'_ge',label:'大于等于'},
  88. {value:'_le',label:'小于等于'},
  89. {value:'_between',label:'介于以下项之间'},
  90. {value:'_null',label:'为空'},
  91. {value:'_not_null',label:'不为空'}
  92. ],
  93. dateOperation:[
  94. {value:'_eq',label:'正好是'},
  95. {value:'_ne',label:'不是'},
  96. {value:'_ge',label:'晚于'},
  97. {value:'_le',label:'早于'},
  98. {value:'_between',label:'介于以下时间之间'},
  99. {value:'_null',label:'为空'},
  100. {value:'_not_null',label:'不为空'}
  101. ]
  102. }
  103. },
  104. mounted : function() {
  105. this.$emit('regist-component', this);
  106. this.operationList =
  107. this.dataType == 'string'? this.stringOperation :
  108. this.dataType == 'number'? this.numberOperation :
  109. this.dataType == 'date'? this.dateOperation :
  110. this.stringOperation;
  111. },
  112. computed: {
  113. defaultTheme () {
  114. return this.$store.state.config.defaultTheme
  115. }
  116. },
  117. methods: {
  118. addFilter (optionIndex) {
  119. this.option.optionList.splice(optionIndex+1,0,{
  120. inputValue:'',
  121. filterMode:'_eq'
  122. })
  123. },
  124. removeFilter (optionIndex) {
  125. this.option.optionList.splice(optionIndex,1);
  126. },
  127. hasFilter () {
  128. if(this.option.inputValue || this.option.subInputValue){
  129. return true;
  130. }else{
  131. if(this.option.optionList && this.option.optionList.length){
  132. for(var i = 0; i < this.option.optionList.length; i++){
  133. if (this.option.optionList[i].inputValue) {
  134. return true;
  135. }
  136. }
  137. }
  138. return false;
  139. }
  140. },
  141. doSubmit () {
  142. var option = {
  143. prop: this.prop,
  144. option: this.option,
  145. label: this.label
  146. };
  147. for (var i = 0; i < this.operationList.length; i++) {
  148. if (this.option.filterMode == this.operationList[i].value) {
  149. option.operationLabel = this.operationList[i].label;
  150. break;
  151. }
  152. }
  153. this.$emit('apply-option', option)
  154. this.visible = false;
  155. },
  156. sortOrder (sort) {
  157. var option = {
  158. prop: this.prop,
  159. sort: sort
  160. };
  161. if(this.mirrorProp) {
  162. option['mirrorProp'] = this.mirrorProp
  163. }
  164. this.$emit('sort-order', option);
  165. this.visible = false;
  166. },
  167. clearFilter () {
  168. this.option = {
  169. inputValue:'',
  170. subInputValue:'',
  171. filterMode:'_eq',
  172. optionList:[{
  173. inputValue:''
  174. }]
  175. }
  176. },
  177. onPaste(e,index){
  178. var _this = this;
  179. var rows = e.clipboardData.getData('text').split('\n');
  180. //去除最后一位空位
  181. if (!rows[rows.length-1]) {
  182. rows.splice(rows.length-1,1);
  183. }
  184. //去重
  185. var obj = {};
  186. var resultRows = []
  187. rows.forEach(function(row){
  188. if(!obj[row]){
  189. resultRows.push(row);
  190. }
  191. obj[row]=true;
  192. });
  193. if(resultRows && resultRows.length){
  194. resultRows.forEach(function(row,rowIndex){
  195. if (_this.option.optionList.length<=index+rowIndex) {
  196. _this.option.optionList.push({inputValue:row})
  197. }else{
  198. _this.option.optionList[index+rowIndex].inputValue = row;
  199. }
  200. });
  201. }
  202. }
  203. }
  204. }
  205. </script>
  206. <style lang="scss" scoped>
  207. @import '@/assets/scss/element-variables.scss';
  208. h3{
  209. margin: 10px 0;
  210. }
  211. .header-tools-title{
  212. display: flex;
  213. align-items: center;
  214. justify-content: space-between;
  215. line-height: 1.1;
  216. white-space: normal;
  217. word-break: break-word;
  218. }
  219. .header-tools-title>span:first-child{
  220. display:-webkit-box;
  221. overflow:hidden;
  222. white-space:normal !important;
  223. text-overflow:ellipsis;
  224. word-wrap:break-word;
  225. -webkit-line-clamp:2;
  226. -webkit-box-orient:vertical;
  227. }
  228. .header-tools-title i{
  229. cursor: pointer;
  230. }
  231. .filter-mode-select{
  232. width: 100px;
  233. }
  234. .filter-mode-select ::v-deep .el-input .el-input__inner{
  235. padding-left: 0px;
  236. border: none;
  237. }
  238. .header-tools-footer{
  239. margin-top: 10px;
  240. }
  241. .header-tools-order {
  242. border-bottom: 1px solid #EBEEF5;
  243. padding-bottom: 10px;
  244. font-size: $--font-size-small;
  245. .order-item {
  246. padding-top: 3px;
  247. padding-bottom: 3px;
  248. }
  249. ::v-deep div{
  250. padding: 5px 0px;
  251. border-radius: 4px;
  252. cursor: pointer;
  253. }
  254. ::v-deep div:hover{
  255. background-color: #409EFF;
  256. color: white;
  257. }
  258. }
  259. .has-search{
  260. color: #409EFF;
  261. }
  262. .header-tools-body{
  263. max-height: 320px;
  264. overflow: auto;
  265. scrollbar-width: none; /* firefox */
  266. -ms-overflow-style: none; /* IE 10+ */
  267. ::v-deep i {
  268. color: #409EFF;
  269. margin-left: 10px;
  270. font-size: 16px;
  271. }
  272. }
  273. .header-tools-body::-webkit-scrollbar {
  274. display: none; /* Chrome Safari */
  275. }
  276. .el-table .header-tools-title .caret-wrapper .sort-caret{
  277. border-top-color: transparent;
  278. border-bottom-color: transparent;
  279. }
  280. .el-table .ascending .header-tools-title .sort-caret.ascending {
  281. border-bottom-color: #409EFF;
  282. }
  283. .el-table .descending .header-tools-title .sort-caret.descending {
  284. border-top-color: #409EFF;
  285. }
  286. .el-input+.el-input,
  287. .option-list-input+.option-list-input{
  288. margin-top: 4px;
  289. }
  290. .el-select-dropdown__item {
  291. font-size: $--font-size-small;
  292. }
  293. </style>
  294. <style>
  295. .header-tools-tag{
  296. background-color: #ecf5ff;
  297. color: #409eff;
  298. border: 1px solid #d9ecff;
  299. padding: 9px 15px;
  300. line-height: 1;
  301. height: 32px;
  302. margin-top: 5px;
  303. }
  304. .header-tools-tag+.header-tools-tag{
  305. margin-bottom: 0px;
  306. margin-left: 10px;
  307. }
  308. .header-tools-tag .el-icon-close{
  309. color: #409eff;
  310. }
  311. .header-tools-tag .el-tag__close:hover{
  312. background-color: #409eff;
  313. color: #FFFFFF;
  314. }
  315. .header-tools-tag-field{
  316. width: auto;
  317. max-width: 50%;
  318. overflow: auto;
  319. display: inline-block;
  320. vertical-align: top;
  321. margin: -5px 10px 0px 10px;
  322. }
  323. </style>
  324. //////////////////////////////////element-variables.scss//////////////////////////////////
  325. // zhimi variables
  326. $zm-size-base: 13px;
  327. // element variables
  328. /* 改变主题色变量 */
  329. $--color-primary: #1D4ED8;
  330. $--color-success: #047857;
  331. $--color-warning: #D97706;
  332. $--color-danger: #B91C1C;
  333. $--color-info: #7F8082;
  334. // 字体
  335. // $--font-size-extra-large: 20px;
  336. // // 18px
  337. // $--font-size-large: 18px;
  338. // // 16px
  339. // $--font-size-medium: 16px;
  340. // // 14px
  341. $--font-size-base: $zm-size-base;
  342. // // 13px
  343. // $--font-size-small: 13px;
  344. // // 12px
  345. // $--font-size-extra-small: 12px;
  346. // // 500
  347. // $--font-weight-primary: 500;
  348. // // 100
  349. // $--font-weight-secondary: 100;
  350. // // 24px
  351. // $--font-line-height-primary: 2;
  352. // // 16px
  353. // $--font-line-height-secondary: 1.12;
  354. $--menu-item-font-size: 14px;
  355. /* 改变 icon 字体路径变量,必需 */
  356. $--font-path: '~element-ui/lib/theme-chalk/fonts';
  357. @import "~element-ui/packages/theme-chalk/src/index";