第二版啦(^U^)ノ~YO
因爲項目的功能愈來愈多,開始注重細節的優化和可延展性,
主要方向是將複用的代碼集成一個組件。css
如下數據都是在vue(^2.5)+vuex(^2.3)+element-ui(^2.3)+webpack(^3.7)+axios(v0.16)環境下測試。
因爲有不少table都是要請求列表總數,包括請求列表也是千篇一概。一開始用的是Eventbus
註冊了共用組件,後來感受對非列表的組件來講是累贅,才改用mixins,既作到了通用,還能複寫。
雖然這個方法我的仍是不太滿意。。。求更好ideahtml
in @/componens/mixins/TableList.js
vue
export default{ data(){ return { isLoading: false } }, methods: { getTotal(response){ // 加個loading狀態 this.isLoading = !this.isLoading // 開始請求列表 this.getTableList() }, getList(response){ // 結束loading狀態 this.isLoading = !this.isLoading }, getTableListCount(total){ this.$http.get(total.api[0],{}).then((response) => { if(response.data && typeof response.data === 'object'){ // 成功獲取數量回調 this.getTotal(response) } }).catch(() => {}) }, getTableList(){ this.$http.get(total.api[1],{}).then((response) => { if(response.data && typeof response.data === 'object'){ // 成功獲取列表回調 this.getList(response) } }).catch(() => {}) } } };
在組件內引用:webpack
import TableListMX from '@/components/mixins/TableList'; export default{ mixins: [TableListMX], methods: { getStart(){ this.getTableListCount({ api: ['list_count', 'list'] }) } } }
項目後臺固然少不了表單,聯繫到數據輸入,這時候限制輸入內容顯得尤其必要。若是每一個輸入框都在輸入時作提示就顯得累贅,因此用了指令去限制輸入。
這裏舉例一個限制小數點位數的自定義指令(參考大佬地址)ios
in @directives/InputNumDigit
git
/* @directive 輸入框限制範圍:小數點個數 or 整數 @param {data-index} 若是是數組要加入index @param {data-dotrange} */ // 尋找當前dom let FindElement = (parent, selector) => { return parent.tagName.toLowerCase() === selector ? parent : parent.querySelector(selector); }; // 設置組件中的指定屬性的值 let setValue = function(exp, value, context) { value = isNaN(value) ? '' : value new Function('context', 'value', `context.${exp} = value`)(context, value) }; export default{ bind: function(el, { expression }, { context }){ let $input = FindElement(el, 'input'); el.$input = $input; // 初始化lastValue $input.lastValue = $input.value // 經過dataset 判斷是否容許小數點 let allowDot = !!$input.dataset.dotrange, keys = $input.dataset.keys || -1,// 若是是數組則加入索引 dotRange = $input.dataset.dotrange || `{0,2}`, // 默認 pattern = `^[0-9]+${allowDot ? `(.[0-9]${dotRange})?` : ''}$`, new_expression = expression; if (!expression) { throw new TypeError('請綁定expression') } // 循環 if(keys !== -1){ new_expression = expression.replace(/\[.*?\]/, `[${keys}]`) } console.log(new_expression) $input.handleInputEvent = function(e) { setTimeout(() => { if (e.target.value === '') { setValue(new_expression, '', context) // 遇到非法數值,則重置 e.target.value = '' } else if (e.target.value !== '' && !new RegExp(pattern).test(e.target.value)) { setValue(new_expression, parseFloat(e.target.lastValue), context) // 遇到非法數值,則重置爲lastValue e.target.value = e.target.lastValue if (allowDot) { $input.title = `小數點後最多${dotRange.replace(/[}{]/g, '').split(',')[1]}位` } } e.target.lastValue = e.target.value }, 0) } $input.addEventListener('input', $input.handleInputEvent, false) }, unbind(el) { el && el.$input.removeEventListener('input', el.$input.handleInputEvent, false) } };
全局註冊:web
import InputNumDigit from '@/directives/InputNumDigit' Vue.directive('num-digit', InputNumDigit)
引用:vuex
<!-- 最多隻能輸入三位小數 --> <el-input v-model.number.trim="rate" v-num-digit="setForm.rate" data-dotrange="{0,3}" type="number"></el-input>
有個瑕疵,這個指令只兼容了第一層for循環時的狀況,沒有考慮到更復雜的狀況
好比,將數字轉換成千分位express
let ToThousands = (val) => {// 數字轉換成千分位 if(!val || val === 0 || isNaN(val)){ return val }else{ let num = 0; if(val.toString().indexOf ('.') !== -1){// 帶小數點 num = val.toLocaleString() }else{ num = val.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,'); } return num; } }; Vue.filter('ToThousands', ToThousands); // or 全局通用 Vue.prototype.$toThousands = ToThousands;
表單驗證少不了,列幾個在後臺經常使用的,放在store能夠隨時調用element-ui
let validator = {// 驗證信息 mobile: (rule, value, callback) => {// 手機號碼 let reg = /^1[3|4|5|6|7|8|9][0-9]{9}$/; if(!reg.test(value)){ callback(new Error("請輸入正確手機號碼")) }else{ callback() } }, idcard: (rule, value, callback) => {// 身份證號碼 let dalu_reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,// 大陸 xianggang_reg = /[A-Z]{1,2}[0-9]{6}([0-9A])/,// 香港 aomen_reg = /^[1|5|7][0-9]{6}\([0-9Aa]\)/,// 澳門 taiwan_reg = /[A-Z][0-9]{9}/;// 臺灣 if(!dalu_reg.test(value) && !xianggang_reg.test(value) && !aomen_reg.test(value) && !taiwan_reg.test(value)){ callback(new Error("請輸入正確身份證號碼")) }else{ callback() } }, noChinese: (rule, value, callback) => {// 英文和數字 let reg = /^[A-Za-z0-9]+$/g; if(!reg.test(value)){ callback(new Error("不能輸入中文!")) }else{ callback() } }, limitNumber: (rule, value, callback) => {// 限制數字大小 if(value < 0 || value >= 10000000){ callback(new Error("最多輸入7位有效數字")) }else if(isNaN(value)){ callback(new Error("請輸入數字")) }else{ callback() } }, limitPercent: (rule, value, callback) => {// 限制百分比 if(value < 0 || value > 100){ callback(new Error("請輸入0~100之間的數字")) }else{ callback() } } };
let dateLimit = { beforeToday: {// 今天以前:不包含今天 disabledDate(time) { return time.getTime() > Date.now() - 8.64e7; } }, beforeTomorrow: {// 明天以前:包含今天 disabledDate(time) { return time.getTime() > Date.now(); } }, afterToday: {// 今天以後:包含今天 disabledDate(time) { return time.getTime() < Date.now() - 8.64e7; } }, afterTomorrow: {// 明天以後:不包含今天 disabledDate(time) { return time.getTime() < Date.now(); } } };
<!-- 經過`page-size`與輸入框同一個參數控制 --> <el-pagination class="sl-page" layout="prev, pager, next, jumper, total, slot" @current-change="handleCurrentChange" :current-page.sync="params.pager" :page-size="params.count" :total="TOTAL"> <span class="resize"> <span>每頁記錄數:</span> <el-input type="number" size="small" v-model.number="params.count" @change="handleSearch"></el-input> </span> </el-pagination>
export defalt{ data(){ return { TOTAL: 100, params: { pager: 1, count: 10 } } }, methods: { handleSearch(){//頁數改變 if(this.parmas.count <= 0 || !this.parmas.count || String(this.parmas.count).indexOf(".") !== -1){ //小於等於零or爲空or小數點時不刷新數據 return false; } this.parmas.pager = 1; this.getList() }, handleCurrentChange(){//頁碼改變 this.getList() } } };
.sl-page { text-align: center; padding-top: 20px; } .sl-page .resize { width: 60px; } .sl-page .resize .el-input__inner { height: 28px; padding: 0 5px; }
單個radio能夠不勾選效果
複合:
<div class="fake-checkbox"> <el-radio v-model="isCheck" :label="1">是否勾選</el-radio> <el-checkbox v-model="isCheck" :false-label="0" :true-label="1" @change="handleSearch">是否勾選</el-checkbox> </div>
.fake-checkbox{ position: relative; display: inline-block; } .fake-checkbox .el-checkbox, .fake-checkbox .el-radio{ width: 55px; } .fake-checkbox .el-radio__label{ padding-left: 5px; } .fake-checkbox .el-checkbox{ position: absolute; top: 0; right: 0; opacity: 0; }
.el-select-dropdown .popper__arrow { transform: none !important; }
.sl-required .el-form-item__label:before { content: '*'; color: #fa5555; margin-right: 4px; }
<el-form-item class="sl-required">...</el-form-item>
.non-arrow input[type="number"]::-webkit-outer-spin-button, .non-arrow input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
<el-input class="non-arrow" type="number"></el-input>