如今也算上暫時閒下來了。算算已經很久沒寫文章了。這篇文章記錄下我使用的一些前端小功能吧。若有錯誤,請及時指出。javascript
開發中要用到數字上下滾動的組件。在github
上找了找這種功能。找到了一個vue-digitroll。週末花了一下午的時間研究了vue-digitroll
的源碼,很不錯。vue-digitroll
並且還作了瀏覽器兼容。最終沒有用在項目裏,緣由有三點:php
vue-digitroll
雖然很輕量,但畢竟也要安裝。安裝了就要多少佔點體積。基於上面三點考慮,我就參考了源碼實現,本身寫了一個簡單的,易於理解的小組件。css
大概原理就是數字轉爲字符串,數字定高,寬度是本身的寬度。循環0到9,超出就往下排。經過
overflow:hidden
隱藏超出的數字。經過傳入的數字找到對應數字的高度位置。translateY
實現滾動效果。html
下面就貼出來源碼:前端
<template>
<div class="roll-wrap" :style="{fontSize:`${cellHeight}px` }">
<ul class="roll-box">
<li
class="roll-item"
v-for="(item, index) in numberArr"
:key="index"
:style="{ height: `${cellHeight}px`,lineHeight:`${cellHeight}px`}"
>
<!--小數點或其餘狀況-->
<div v-if="isNaN(parseFloat(item))">{{ item }}</div>
<div v-else :style="getStyles(index)">
<!--數字0到9-->
<div
:style="{ height: `${cellHeight}px`,lineHeight:`${cellHeight}px`}"
v-for="(subItem,subIndex) in oneToNineArr"
:key="subIndex"
>{{ subItem }}</div>
</div>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
// 高度,默認30
cellHeight: {
type: Number,
default: 30
},
// 須要傳入的滾動數字
rollNumber: {
type: [String, Number],
default: 0
},
// 滾動持續時間,單位ms.默認1.5s
dur: {
type: Number,
default: 1500
},
// 緩動函數,默認ease
easeFn: {
type: String,
default: 'ease'
}
},
data () {
const { rollNumber } = this
return {
// 傳入的數字
number: `${rollNumber}`,
// 傳入的數字解析爲數組
numberArr: [],
// 偏移量
numberOffsetArr: [],
// 0到9數組
oneToNineArr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
}
},
created () {
this.numberArr = this.number.split('')
this.resetState(this.numberArr.length)
},
watch: {
rollNumber (value, oldVal) {
this.number = `${value}`
this.numberArr = `${value}`.split('')
this.resetState(this.numberArr.length)
}
},
methods: {
resetState (len) {
const newArr = new Array(len).join(',').split(',')
this.numberOffsetArr = newArr.map(() => 0)
// 延遲執行動畫
setTimeout(() => {
// 設置傳入的數字下標對應偏移量,從新賦值
this.numberArr.forEach((num, i) => {
this.$set(this.numberOffsetArr, i, num * this.cellHeight)
})
}, 30)
},
getStyles (index) {
const style = { transition: `${this.easeFn} ${this.dur}ms`, transform: `translate(0%, -${this.numberOffsetArr[index]}px)` }
return style
}
}
}
</script>
<style lang="stylus" scoped>
.roll-wrap
ul.roll-box
display flex
padding 0
margin 0
text-align center
overflow hidden
li
overflow hidden
</style>
複製代碼
使用方式也很簡單,以下:vue
<number-roll :roll-number="9999" />
複製代碼
具體參考 JavaScript 浮點數陷阱及解法和number-precision 這篇文章和number-precision開源庫。java
我也看了看源碼,進行了一些測試,摘出來了一些,下面就貼一下我摘出來的源碼:node
/**
* 解決浮點運算問題,避免小數點後產生多位數和計算精度損失。
*/
export default {
/**
* 返回數字長度
* @param {*number} num Input number
*/
digitLength (num) {
const len = (num.toString().split('.')[1] || '').length
return len > 0 ? len : 0
},
/**
* 把小數轉成整數,若是是小數則放大成整數
* @param {*number} num 輸入數
*/
float2Fixed (num) {
return Number(num.toString().replace('.', ''))
},
/**
* 精確加法
* plus(0.1, 0.2) // = 0.3, not 0.30000000000000004
*/
plus (num1, num2) {
const baseNum = Math.pow(10, Math.max(this.digitLength(num1), this.digitLength(num2)))
return (num1 * baseNum + num2 * baseNum) / baseNum
},
/**
* 精確減法
* minus(1.0, 0.9) // = 0.1, not 0.09999999999999998
*/
minus (num1, num2) {
const baseNum = Math.pow(10, Math.max(this.digitLength(num1), this.digitLength(num2)))
return (num1 * baseNum - num2 * baseNum) / baseNum
},
/**
* 精確乘法
* times(3, 0.3) // = 0.9, not 0.8999999999999999
*/
times (num1, num2) {
const num1Changed = this.float2Fixed(num1)
const num2Changed = this.float2Fixed(num2)
const baseNum = this.digitLength(num1) + this.digitLength(num2)
const leftValue = num1Changed * num2Changed
return leftValue / Math.pow(10, baseNum)
},
/**
* 精確除法
* divide(1.21, 1.1) // = 1.1, not 1.0999999999999999
*/
divide (num1, num2) {
const num1Changed = this.float2Fixed(num1)
const num2Changed = this.float2Fixed(num2)
return (num1Changed / num2Changed) * Math.pow(10, this.digitLength(num2) - this.digitLength(num1))
},
/**
* 四捨五入
* round(0.105, 2); // = 0.11, not 0.1
*/
round (num, ratio) {
const base = Math.pow(10, ratio)
return this.divide(Math.round(this.times(num, base)), base)
}
}
複製代碼
由於項目裏使用axios
進行了全局異常處理的提示,不需特殊處理的狀況下,沒有必要進行try{}catch{}
代碼塊包裝了。由於大多數按鈕提交的時候要增長loading,就可使用fianlly
如下方式簡化代碼。ios
this.submitLoading = true
if(this.submitLoading) return
const res = await submitForm({name:'zhangsan',age:'20'}).finally(() => { this.submitLoading = false })
複製代碼
不少開源庫中都使用了
element
的<el-scrollbar/>
組件。這個組件真的好用,若是你有定高可是須要顯示滾動條實現滾動的需求。就能夠很簡單的實現好看的滾動條。好比以下面的代碼:git
<el-scrollbar style="height: 300px;">
<el-tree
:data="data"
/>
</el-scrollbar>
複製代碼
列表的搜索功能是必備的。在使用庫的時候避免大量引入組件的標籤,封裝一些不那麼複雜的搜索小組件,使用起來很方便。好比下面的代碼:
<template>
<el-row type="flex" align="middle">
<el-col :span="24">
<el-form @keyup.enter.native="querySearch()" @submit.native.prevent class="flex-center" :inline="inline">
<el-form-item v-for="(item,index) in formArr" :key="index" :label="item.label">
<el-select v-if="item.tagName === 'select'" v-model="item.value" placeholder="請選擇">
<el-option v-for="item in item.options || []" :key="item.value" :value="item.value" :label="item.label" />
</el-select>
<el-input v-else v-model="item.value" :placeholder="item.placeholder"></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" type="warning" @click="querySearch()">查詢</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
<script>
import { deepCopy } from 'utils/utils'
export default {
props: {
searchColumns: {
type: Array,
default () {
return []
}
},
inline: {
type: Boolean,
default: true
}
},
data () {
return {
formArr: []
}
},
methods: {
querySearch () {
const obj = {}
this.formArr.forEach(el => {
obj[el.prop] = el.value
})
this.$emit('query-search', obj)
}
},
watch: {
searchColumns: {
handler (val) {
this.formArr = deepCopy(this.searchColumns)
},
deep: true,
immediate: true
}
}
}
</script>
複製代碼
使用起來也很簡單:
<simple-search :searchColumns="searchColumns" @query-search="querySearch" />
export default {
data () {
return {
// 搜索條件
condition: {}
// 搜索列
searchColumns: [
{
label: '名稱',
prop: 'name',
value: '',
placeholder: '請輸入名稱'
}
}
},
methods: {
querySearch (queryForm) {
this.condition = queryForm
this.getList()
}
}
}
複製代碼
mixins
真是個好東西,善於使用mixins
能夠簡化很多代碼。加快Vue項目的開發速度這篇文章挺不錯。可是mixins
不能濫用,不要在全局中使用。
由於大部分後臺列表頁面都要請求列表,都要分頁,加載loading等,咱們沒有必要在每一個Vue組件下面都寫這些屬性。下面是我用mixins
的實現了一些簡化這些代碼的功能(基於ElementUI)。若是每次切換路由的時候,須要記住當前用戶離開這個列表頁面以前的頁碼,可使用localStorage
來存儲頁碼。
/*
* 分頁mixins
*/
export default {
data () {
return {
// 分頁
pagination: {
// 當前頁
page: 1,
// 頁長
size: 10,
// 總個數
total: 0,
// 分頁佈局
layout: 'prev,pager,next,total,jumper'
},
// 增,刪,改按鈕loading
load: {
addLoading: false,
deleteLoading: false,
editLoading: false
},
// 列表loading
listLoading: true
}
},
created () {
if (!(Object.prototype.toString.call(this.getList) === '[object Function]')) {
throw new Error('請在組件內定義getList方法加載數據!')
}
},
methods: {
// 改變頁碼handle
pageChange (val) {
this.pagination.page = val
this.getList()
},
// 移除一條數據後從新獲取列表數據
getListForDelSingle (list = [], index = 0) {
list.splice(index, 1)
// 若是當前頁無數據
if (list.length <= 0) {
this.pagination.page--
if (this.pagination.page <= 0) {
this.pagination.page = 1
}
}
this.getList()
},
// 移除多條數據後從新獲取列表數據
getListForDeltMany (delLen, listLen) {
if (!delLen || !listLen) return
if (delLen >= listLen) {
this.pagination.page--
if (this.pagination.page <= 0) {
this.pagination.page = 1
}
}
this.getList()
}
}
}
複製代碼
若是說項目中沒有還安裝
lodash
的話,均可以加如下的,很輕量,很好用。可以節省不少時間。還有就是好多開源庫的工具方法都很是棒,好比說Element
,iview
,ant-design
,vant
等均可以參考學習或者在項目中直接拿來用。
form
表單對象有不少時候須要初始化,若是手寫代碼一行一行的修改的話,代碼會很是冗餘。若是說form
表單不是很複雜的話,就能夠用下面這種方式實現表單初始化效果:this.userForm.name = ''
this.userForm.pwd = ''
複製代碼
function initForm (form = {}, init = { num: 0, str: '' }) {
const newForm = {}
const toString = Object.prototype.toString
for (const [key, value] of Object.entries(form)) {
if (toString.call(value) === '[object String]') {
newForm[key] = init.str
} else if (toString.call(value) === '[object Number]') {
newForm[key] = init.num
} else if (toString.call(value) === '[object Array]') {
newForm[key] = []
} else if (toString.call(value) === '[object Object]') {
newForm[key] = {}
}
}
return newForm
}
複製代碼
function getFlattenDeepList (nodes = []) {
let list = []
nodes.forEach(item => {
list.push(item)
if (item.children && item.children.length) {
const tempList = getFlattenDeepList(item.children)
list = [...list, ...tempList]
}
})
return list
}
複製代碼
function getParentIdListByLeafId (leafId, nodes = [], newNodes = []) {
if (!leafId) return []
for (let i = 0, len = nodes.length; i < len; i++) {
const tempList = newNodes.concat()
tempList.push(nodes[i].id)
// 找到匹配返回結果
if (leafId === nodes[i].id) {
return tempList
}
if (nodes[i].children && nodes[i].children.length) {
const result = getParentIdListByLeafId(leafId, nodes[i].children, tempList)
if (result) return result
}
}
}
複製代碼
let arr = [
{ id: 1, pid: '', name: '1AA' },
{ id: 2, pid: '', name: '2AA' },
{ id: 3, pid: '', name: '3AA' },
{ id: 4, pid: 1, name: '4AA' },
{ id: 5, pid: 2, name: '5AA' },
{ id: 6, pid: 3, name: '6AA' },
{ id: 7, pid: 4, name: '7AA' },
{ id: 8, pid: 1, name: '8AA' },
{ id: 9, pid: 5, name: '9AA' }
]
const newArr = []
arr.forEach(el => {
el.children = []
if (!el.pid) {
newArr.push(el)
} else {
const parent = arr.find(_ => _.id === el.pid)
parent.children.push(el)
}
})
複製代碼
正則表達式自己是很複雜的(其實我也不是很懂…),關於須要正則表達式來驗證的功能。若是項目時間比較緊,拿一些比較嚴謹的開源庫裏的正則直接用是能夠的。推薦鐵皮鐵皮飯盒老師的正則大全這個庫,幾千個star
。應該是通過很嚴謹的驗證的,不要在經過網上隨便搜出來的正則拿來直接用,我始終感受不是正確的。不過正則確實是應該抽出一大段時間好好學的。
使用好Vue
的語法糖(v-model
,v-on
,v-bind
)也能夠簡化代碼的編寫。好比說要封裝<el-select/>
組件修改樣式或進行特殊定製。就能夠像下面代碼這樣(參考自Vue-Element-Admin
):
<template>
<el-select ref="dragSelect" v-model="selectVal" v-bind="$attrs" v-on="$listeners" multiple">
<slot />
</el-select>
</template>
<script>
import Sortable from 'sortablejs'
export default {
name: 'DragSelect',
props: {
value: {
type: Array,
required: true
}
},
computed: {
selectVal: {
get() {
return [...this.value]
},
set(val) {
this.$emit('input', [...val])
}
}
}
}
</script>
複製代碼
<el-drag-select v-model="value" style="width:500px;" multiple placeholder="請選擇">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-drag-select>
<script>
import ElDragSelect from '@/components/DragSelect' // base on element-ui
export default {
name: 'DragSelectDemo',
components: { ElDragSelect },
data() {
return {
value: ['Apple'],
options: [{
value: 'Apple',
label: 'Apple'
}]
}
}
}
</script>
複製代碼
每一個 Vue 實例在被建立以前都要通過一系列的初始化過程。例如須要設置數據監聽、編譯模板、掛載實例到 DOM、在數據變化時更新DOM等。其實理解了初始化順序,就能夠知道在鉤子函數裏該作什麼事情了。這裏參考Vue生命週期。
文章排版使用MD2All。使用起來很簡單,把在掘金上寫的文字和代碼複製到左側黑色區域,而後點擊一鍵排版,而後點保存,複製帶樣式的文字和代碼後,在粘貼回來就能夠了。注意如下,最好本身原來的文章留個備份,否則生成的不少樣式代碼沒法理解。
有一個坑須要注意如下當使用
``來解析代碼的時候,注意後面不要加
html或者
js了。否則
MD2All`解析不友好。