元素點(diǎn)擊范圍擴(kuò)展指令 v-expandClick
使用該指令可以隱式的擴(kuò)展元素的點(diǎn)擊范圍,由于借用偽元素實(shí)現(xiàn),故不會(huì)影響元素在頁(yè)面上的排列布局。
可傳入的參數(shù)為:上右下左擴(kuò)展的范圍,單位 px,默認(rèn)向外擴(kuò)展 10px。指令的代碼如下:
export default function (el, binding) {
const s = document.styleSheets[document.styleSheets.length - 1]
const DEFAULT = -10 // 默認(rèn)向外擴(kuò)展10px
const ruleStr = `content:"";position:absolute;top:-${top || DEFAULT}px;bottom:-${bottom || DEFAULT}px;right:-${right || DEFAULT}px;left:-${left || DEFAULT}px;`
const [top, right, bottom, left] = binding.expression && binding.expression.split(',') || []
const classNameList = el.className.split(' ')
el.className = classNameList.includes('expand_click_range') ? classNameList.join(' ') : [...classNameList, 'expand_click_range'].join(' ')
el.style.position = el.style.position || "relative"
if (s.insertRule) {
s.insertRule('.expand_click_range::before' + '{' + ruleStr + '}', s.cssRules.length)
} else { /* IE */
s.addRule('.expand_click_range::before', ruleStr, -1)
}
}
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| top, right, bottom, left | 上右下左擴(kuò)展寬度(逗號(hào)分割) | |||
| 單位px | 10,10,10,10 | String | 可填 |
然后你可以在模板中任何元素上使用新的 v-expandClick property,如下:
<div v-expandClick="20,30,40,50" @click="glabClickoutside"> 點(diǎn)擊范圍擴(kuò)大</div>
文本內(nèi)容復(fù)制指令 v-copy
使用該指令可以復(fù)制元素的文本內(nèi)容(指令支持單擊復(fù)制 v-copy、雙擊復(fù)制 v-copy.dblclick、點(diǎn)擊icon復(fù)制 v-copy.icon 三種模式),不傳參數(shù)時(shí),默認(rèn)使用單擊復(fù)制。
指令的代碼如下:
export default {
bind (el, binding) {
// 雙擊觸發(fā)復(fù)制
if (binding.modifiers.dblclick) {
el.addEventListener('dblclick', () => handleClick(el.innerText))
el.style.cursor = 'copy'
}
// 點(diǎn)擊icon觸發(fā)復(fù)制
else if (binding.modifiers.icon) {
if (el.hasIcon) return
const iconElement = document.createElement('i')
iconElement.setAttribute('class', 'el-icon-document-copy')
iconElement.setAttribute('style', 'margin-left:5px')
el.appendChild(iconElement)
el.hasIcon = true
iconElement.addEventListener('click', () => handleClick(el.innerText))
iconElement.style.cursor = 'copy'
}
// 單擊觸發(fā)復(fù)制
else {
el.addEventListener('click', () => handleClick(el.innerText))
el.style.cursor = 'copy'
}
}
}
function handleClick (text) {
// 創(chuàng)建元素
if (!document.getElementById('copyTarget')) {
const copyTarget = document.createElement('input')
copyTarget.setAttribute('style', 'position:fixed;top:0;left:0;opacity:0;z-index:-1000;')
copyTarget.setAttribute('id', 'copyTarget')
document.body.appendChild(copyTarget)
}
// 復(fù)制內(nèi)容
const input = document.getElementById('copyTarget')
input.value = text
input.select()
document.execCommand('copy')
// alert('復(fù)制成功')
}
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| dblclick | 雙擊復(fù)制文本內(nèi)容 | / | String | 可選 |
| icon | 單擊icon復(fù)制文本內(nèi)容 | / | String | 可選 |
然后你可以在模板中任何元素上使用新的 v-copy property,如下:
<div v-copy> 單擊復(fù)制 </div>
<div v-copy.dblclick> 雙擊復(fù)制 </div>
<div v-copy.icon> icon復(fù)制 </div>
元素全屏指令 v-screenfull
全屏指令,點(diǎn)擊元素進(jìn)行全屏/退出全屏的操作。支持元素后面是否插入 element-ui 的全屏圖標(biāo) el-icon-full-screen。
指令的代碼如下:
import screenfull from 'screenfull'
export default {
bind (el, binding) {
if (binding.modifiers.icon) {
if (el.hasIcon) return
// 創(chuàng)建全屏圖標(biāo)
const iconElement = document.createElement('i')
iconElement.setAttribute('class', 'el-icon-full-screen')
iconElement.setAttribute('style', 'margin-left:5px')
el.appendChild(iconElement)
el.hasIcon = true
}
el.style.cursor = el.style.cursor || 'pointer'
// 監(jiān)聽(tīng)點(diǎn)擊全屏事件
el.addEventListener('click', () => handleClick())
}
}
function handleClick () {
if (!screenfull.isEnabled) {
alert('瀏覽器不支持全屏')
return
}
screenfull.toggle()
}
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| icon | 是否添加 icon | / | String | 可選 |
然后你可以在模板中任何元素上使用新的 v-screenfull property,如下:
<div v-screenfull.icon> 全屏 </div>
元素說(shuō)明指令 v-tooltip
為元素添加說(shuō)明,如同 element-ui 的 el-tooltip(問(wèn)號(hào) icon 在鼠標(biāo)覆蓋后,展示說(shuō)明文字)。
指令的代碼如下:
import Vue from 'vue'
export default function (el, binding) {
if (el.hasIcon) return
const iconElement = structureIcon(binding.arg, binding.value)
el.appendChild(iconElement)
el.hasIcon = true
}
function structureIcon (content, attrs) {
// 拼接綁定屬性
let attrStr = ''
for (let key in attrs) {
attrStr += `${key}=${attrs[key]} `
}
const a = `<el-tooltip content=${content} ${attrStr}><i class="el-icon-question" style="margin:0 10px"></i></el-tooltip>`
// 創(chuàng)建構(gòu)造器
const tooltip = Vue.extend({
template: a
})
// 創(chuàng)建一個(gè) tooltip 實(shí)例并返回 dom 節(jié)點(diǎn)
const component = new tooltip().$mount()
return component.$el
}
參數(shù) Attributes:
參數(shù) 說(shuō)明 默認(rèn)值 類型 可選
content 傳給指令的參數(shù)。例如 v-tooltip:content 中,參數(shù)為 "content" ,tooltip中展示的內(nèi)容為:"content" / String 可選
tootipParams element-ui 支持的 tooltip 屬性 / Object 可選
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| content | 傳給指令的參數(shù)。例如 v-tooltip:content 中,參數(shù)為 "content" ,tooltip中展示的內(nèi)容為:"content" | / | String | 可選 |
| tootipParams | element-ui 支持的 tooltip 屬性 | / | Object | 可選 |
然后你可以在模板中任何元素上使用新的 v-tooltip property,如下:
<div v-tooltip:content='tootipParams'> 提示 </div>
//舉例:
<div v-tooltip:提示內(nèi)容為XXX1> 提示1</div>
<div v-tooltip:提示內(nèi)容為XXX='tootipParams'> 提示2 </div>
//為指令傳入 element-ui 支持的參數(shù):
data() {
return {
tootipParams: {
placement: 'top',
effect: 'light',
}
}
}
文字超出省略指令 v-ellipsis
使用該指令當(dāng)文字內(nèi)容超出寬度(默認(rèn) 100 px)時(shí)自動(dòng)變?yōu)槭÷孕问?。等同于使?css:
width: 100px;
whiteSpace: nowrap
overflow: hidden;
textOverflow: ellipsis;
使用指令效果:
指令的代碼如下:
export default function (el, binding) {
el.style.width = binding.arg || 100 + 'px'
el.style.whiteSpace = 'nowrap'
el.style.overflow = 'hidden';
el.style.textOverflow = 'ellipsis';
}
參數(shù) Attributes:
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| width | 元素寬度 | 100 | Number | 必填 |
然后你可以在模板中任何元素上使用新的 v-ellipsis property,如下:
<div v-ellipsis:100> 需要省略的文字是阿薩的副本阿薩的副本阿薩的副本阿薩的副本</div>
回到頂部指令 v-backtop
使用該指令可以讓頁(yè)面或指定元素回到頂部。
可選指定元素,如果不指定則全局頁(yè)面回到頂部??蛇x在元素偏移多少 px 后顯示 backtop 元素,例如在滾動(dòng) 400px 后顯示回到頂部按鈕。
指令的代碼如下:
export default {
bind (el, binding, vnode) {
// 響應(yīng)點(diǎn)擊后滾動(dòng)到元素頂部
el.addEventListener('click', () => {
const target = binding.arg ? document.getElementById(binding.arg) : window
target.scrollTo({
top: 0,
behavior: 'smooth'
})
})
},
update (el, binding, vnode) {
// 滾動(dòng)到達(dá)參數(shù)值才出現(xiàn)綁定指令的元素
const target = binding.arg ? document.getElementById(binding.arg) : window
if (binding.value) {
target.addEventListener('scroll', (e) => {
if (e.srcElement.scrollTop > binding.value) {
el.style.visibility = 'unset'
} else {
el.style.visibility = 'hidden'
}
})
}
// 判斷初始化狀態(tài)
if (target.scrollTop < binding.value) {
el.style.visibility = 'hidden'
}
},
unbind (el) {
const target = binding.arg ? document.getElementById(binding.arg) : window
target.removeEventListener('scroll')
el.removeEventListener('click')
}
}
參數(shù) Attributes:
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| id | 給需要回到頂部的元素添加的id | / | String | 可選 |
| offset | 偏移距離為 height 時(shí)顯示指令綁定的元素 | / | Number | 可選 |
然后你可以在模板中任何元素上使用新的 v-backtop property,如下表示在 id 為 app 的元素滾動(dòng) 400px 后顯示綁定指令的元素:
<div v-backtop:app="400"> 回到頂部 </div>
也可以這樣使用,表示為一直顯示綁定指令的元素,并且是全局頁(yè)面回到頂部:
<div v-backtop> 回到頂部 </div>
空狀態(tài)指令 v-empty
使用該指令可以顯示缺省的空狀態(tài)??梢詡魅肽J(rèn)圖片(可選,默認(rèn)無(wú)圖片)、默認(rèn)文字內(nèi)容(可選,默認(rèn)為暫無(wú)數(shù)據(jù))、以及標(biāo)示是否顯示空狀態(tài)(必選)。
[圖片上傳中...(image-48bc59-1626230983557-0)]
指令的代碼如下:
import Vue from "vue";
export default {
update (el, binding, vnode) {
el.style.position = el.style.position || 'relative'
const { offsetHeight, offsetWidth } = el
const { visible, content, img } = binding.value
const image = img ? `<img src="${img}" height="30%" width="30%"></img>` : ''
const defaultStyle = "position:absolute;top:0;left:0;z-index:9999;background:#fff;display:flex;justify-content: center;align-items: center;"
const empty = Vue.extend({
template: `<div style="height:${offsetHeight}px;width:${offsetWidth}px;${defaultStyle}">
<div style="text-align:center">
<div>${image}</div>
<div>${content || '暫無(wú)數(shù)據(jù)'}</div>
</div>
</div>`
})
const component = new empty().$mount().$el
if (visible) {
el.appendChild(component)
} else {
el.removeChild(el.lastChild)
}
},
}
參數(shù) Attributes:
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| emptyValue | 包含文字內(nèi)容 content、圖片 img、是否顯示 visible,僅 visible 必傳 | / | Object | 必須 |
然后你可以在模板中任何元素上使用新的 v-empty property,如下傳入對(duì)象 emptyValue:
div style="height:500px;width:500px" v-empty="emptyValue"> 原本內(nèi)容
需要傳入一個(gè)參數(shù)對(duì)象,例如顯示文字為:暫無(wú)列表,圖片路徑為 ../../assets/images/blue_big.png,控制標(biāo)示 visible:
emptyValue = {
content: '暫無(wú)列表',
img: require('../../assets/images/blue_big.png'),
visible: true,
},
徽標(biāo)指令 v-badge
使用該指令在元素右上角顯示徽標(biāo)。
支持配置徽標(biāo)的背景顏色、徽標(biāo)形狀;支持傳入徽標(biāo)上顯示的數(shù)字。
指令的代碼如下:
import Vue from 'vue'
const SUCCESS = '#72c140'
const ERROR = '#ed5b56'
const WARNING = '#f0af41'
const INFO = '#4091f7'
const HEIGHT = 20
let flag = false
export default {
update (el, binding, vnode) {
const { modifiers, value } = binding
const modifiersKey = Object.keys(modifiers)
let isDot = modifiersKey.includes('dot')
let backgroundColor = ''
if (modifiersKey.includes('success')) {
backgroundColor = SUCCESS
} else if (modifiersKey.includes('warning')) {
backgroundColor = WARNING
} else if (modifiersKey.includes('info')) {
backgroundColor = INFO
} else {
backgroundColor = ERROR
}
const targetTemplate = isDot
? `<div style="position:absolute;top:-5px;right:-5px;height:10px;width:10px;border-radius:50%;background:${backgroundColor}"></div>`
: `<div style="background:${backgroundColor};position:absolute;top:-${HEIGHT / 2}px;right:-${HEIGHT / 2}px;height:${HEIGHT}px;min-width:${HEIGHT}px;border-radius:${HEIGHT / 2}px;text-align:center;line-height:${HEIGHT}px;color:#fff;padding:0 5px;">${value}</div>`
el.style.position = el.style.position || 'relative'
const badge = Vue.extend({
template: targetTemplate
})
const component = new badge().$mount().$el
if (flag) {
el.removeChild(el.lastChild)
}
el.appendChild(component)
flag = true
}
}
參數(shù) Attributes:
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| normal、dot | 徽標(biāo)形狀normal為正?;諛?biāo);dot 僅為一個(gè)點(diǎn) | normal | String | 可選 |
| success、error、info、warning | 徽標(biāo)顏色 | error | String | 可選 |
| number | 徽標(biāo)上顯示的數(shù)字 | / | Number | 可選 |
然后你可以在模板中任何元素上使用新的 v-badge property,如下:
<div v-badge.dot.info="badgeCount" style="height:50px;width:50px;background:#999"> </div>
拖拽指令 v-drag
使用該指令可以對(duì)元素進(jìn)行拖拽。
指令的代碼如下:
export default {
let _el = el
document.onselectstart = function() {
return false //禁止選擇網(wǎng)頁(yè)上的文字
}
_el.onmousedown = e => {
let disX = e.clientX - _el.offsetLeft //鼠標(biāo)按下,計(jì)算當(dāng)前元素距離可視區(qū)的距離
let disY = e.clientY - _el.offsetTop
document.onmousemove = function(e){
let l = e.clientX - disX
let t = e.clientY - disY;
_el.style.left = l + "px"
_el.style.top = t + "px"
}
document.onmouseup = e => {
document.onmousemove = document.onmouseup = null
}
return false
}
}
然后你可以在模板中任何元素上使用新的 v-drag property,如下:
<div v-drag> 支持拖拽的元素 </div>
響應(yīng)縮放指令 v-resize
使用該指令可以響應(yīng)元素寬高改變時(shí)執(zhí)行的方法。
指令的代碼如下:
export default {
bind(el, binding) {
let width = '', height = '';
function isReize() {
const style = document.defaultView.getComputedStyle(el);
if (width !== style.width || height !== style.height) {
binding.value(); // 執(zhí)行傳入的方法
}
width = style.width;
height = style.height;
}
el.__timer__ = setInterval(isReize, 300); // 周期性監(jiān)聽(tīng)元素是否改變
},
unbind(el) {
clearInterval(el.__timer__);
}
}
參數(shù) Attributes:
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| resize() | 傳入元素改變 size 后執(zhí)行的方法 | / | Function | 必選 |
然后你可以在模板中任何元素上使用新的 v-resize property,如下:
// 傳入 resize() 方法
<div v-resize="resize"></div>
字符串整形指令 v-format
使用該指令可以修改字符串,如使用 v-format.toFixed 保留兩位小數(shù)、 v-format.price 將內(nèi)容變成金額(每三位逗號(hào)分隔),可以同時(shí)使用,如 v-format.toFixed.price。
例如將數(shù)字 243112.331 變成 243112.33,或 243,112.33。
指令的代碼如下:
export default {
update (el, binding, vnode) {
const { value, modifiers } = binding
if (!value) return
let formatValue = value
if (modifiers.toFixed) {
formatValue = value.toFixed(2)
}
console.log(formatValue)
if (modifiers.price) {
formatValue = formatNumber(formatValue)
}
el.innerText = formatValue
},
}
function formatNumber (num) {
num += '';
let strs = num.split('.');
let x1 = strs[0];
let x2 = strs.length > 1 ? '.' + strs[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2
}
參數(shù) Attributes:
| 參數(shù) | 說(shuō)明 | 默認(rèn)值 | 類型 | 可選 |
|---|---|---|---|---|
| toFixed | 保留兩位小數(shù) | / | String | 可選 |
| price | 整形成金額(三位逗號(hào)分隔) | / | String | 可選 |
然后你可以在模板中任何元素上使用新的 v-format property,如下:
<div v-format.toFixed.price="123333"> 123 </div>
如何使用這些指令?
為了便于管理指令,我們將每個(gè)指令都存在于單獨(dú)的 js 文件中。在項(xiàng)目的 src 下建一個(gè) directives 目錄,目錄下新建 index.js 文件用于引入并注冊(cè)指令。
├── src
| ├── directive
| | ├── index.js
| | ├── backtop.js
| | ├── badge.js
| | ├── copy.js
| | ├── ellipsis.js
| | ├── empty.js
| | ├── expandClick.js
| | ├── screenfull.js
| | └── tooltips.js
| ├── main.js
舉個(gè):
directives 目錄下新建 ellipsis.js 文件:
export default function (el, binding) {
el.style.width = binding.arg || 100 + 'px'
el.style.whiteSpace = 'nowrap'
el.style.overflow = 'hidden';
el.style.textOverflow = 'ellipsis';
}
directives 的 index.js 文件中引入 ellipsis 指令并注冊(cè):
import Vue from 'vue'
import ellipsis from './ellipsis' // 引入指令
// import other directives
const directives = {
ellipsis
// other directives
}
Object.keys(directives).forEach(name => Vue.directive(name, directives[name]))
最后在 mian.js 中引入 index.js 文件:
import '@/directives/index'
這樣就可以正常使用這些指令了:
<div v-指令名稱 />