懒加载
html:
<div v-lazy>
<div style="width: 100%;height: 99vh;background: red"></div>
<div style="width: 100%;height: 50vh;background: orange"></div>
<div style="width: 100%;height: 36vh;background: yellow"></div>
<div style="width: 100%;height: 102vh;background: green"></div>
<div style="width: 100%;height: 14vh;background: cyan"></div>
<div style="width: 100%;height: 50vh;background: blue"></div>
<div style="width: 100%;height: 100vh;background: purple"></div>
</div>
directive:
import Vue from 'vue'
import {Toast} from "vant";
Vue.directive("lazy", (el) => {
let showPage = 1;// 当前展示页数
let maxPage = 1;// 最大页数
let arr = [];
let mission = null;// 正在执行的加载任务
Vue.nextTick(() => {
let height = 0;// 累计高度
for (let item of el.children) {
if (height >= el.clientHeight * maxPage) maxPage++;// 当前页已放满,增加页数
height += item.clientHeight;// 累计高度
let obj = {pageNum:maxPage, height};
arr.push(obj);
if (maxPage > showPage) item.style.display = "none";// 隐藏不展示内容
}
})
// 加载新内容
let changeShowDom = () => {
showPage++;// 增加页数
for (let i in arr) {
// 找到页数对应dom下标,展示对应dom
if (arr[i].pageNum === showPage) el.children[i].style.display = "";
}
}
// 滚动监听
el.onscroll = () => {
if (mission) return;// 阻止连续触发
let scrollTop = el.scrollTop; // 滚动高度
let clientHeight = el.clientHeight; //可见高度
for (let i = arr.length - 1; i > 0; i--) {
if (showPage === arr[i].pageNum && scrollTop + clientHeight >= arr[i].height - 30) {
// 已滚动至当前页面底部
Toast.loading({mask: true, duration: 1000});// 加载动画
changeShowDom();// 加载新内容
mission = setTimeout(() => { mission = null }, 1000);// 1秒后取消监听限制
break;
}
}
if (showPage >= maxPage) el.onscroll = null;// 全部加载完毕,关闭滚动监听
};
})
边框
html:
<div v-border:5.t.r="'red'"></div>
directive:
import Vue from 'vue'
/** 使用方式:border:v-border:width.arr="color"
* width--线宽(不传默认1px)
* arr--画线的方位(不传默认全部)
* color--颜色(不传默认#eaeaea)
*/
Vue.directive("border", (el, binding) => {
let width = binding.arg ? binding.arg : "1";// 线宽(默认1px)
let arr = [];// 画线的方位
let color = binding.value ? binding.value : "#eaeaea";// 颜色(默认#eaeaea)
if (binding.modifiers.t) arr.push("borderTop");// top画线
if (binding.modifiers.r) arr.push("borderRight"); // right画线
if (binding.modifiers.b) arr.push("borderBottom"); // bottom画线
if (binding.modifiers.l) arr.push("borderLeft"); // left画线
if (JSON.stringify(binding.modifiers) === "{}") arr.push("border");// 未指定方位,默认全画
for (let item of arr) {
el.style[item] = `${width}px solid ${color}`;
}
})
效果:
flex布局
html:
<div v-flex.jc.ac class="hp">
<div v-border:5.t.r="'red'" style="width: 50%;height: 10rem;"></div>
</div>
directive:
import Vue from 'vue'
/** 使用方式:v-flex.xx.xx...
* w: 换行
* wr: 反向换行
* rr: 水平反向布局
* c: 垂直布局
* cr: 垂直反向布局
* js: X轴靠前
* jc: X轴居中
* je: X轴靠后
* jb: X轴两端对齐
* ja: X轴元素间隔对齐
* as: Y轴靠前
* ac: Y轴居中
* ae: Y轴靠后
* ab: Y轴文字对齐
*/
Vue.directive("flex", (el, binding) => {
if (el.className.indexOf("flex") !== -1) return;
// 添加类名
el.className += (el.className ? " " : "") + "flex";
// 添加样式
if (binding.modifiers) {
let obj = binding.modifiers;
// flex-flow
let wrap = obj.w ? "wrap" : (obj.wr ? "wrap-reverse" : "nowrap");// 默认:不换行/w:换行/wr:反向换行
if (obj.rr) {
el.style.flexFlow = `row-reverse ${wrap}`; // 水平反向布局
} else if (obj.c) {
el.style.flexFlow = `column ${wrap}`; // 垂直布局
} else if (obj.cr) {
el.style.flexFlow = `column-reverse ${wrap}`; // 垂直反向布局
} else if (obj.w || obj.wr) {
el.style.flexFlow = `row ${wrap}`; // 水平布局
}
// justify-content
if (obj.js) {
el.style.justifyContent = "flex-start"; // 垂直布局时上对齐,水平布局时左对齐
} else if (obj.jc) {
el.style.justifyContent = "center"; // 居中
} else if (obj.je) {
el.style.justifyContent = "flex-end"; // 垂直布局时下对齐,水平布局时右对齐
} else if (obj.jb) {
el.style.justifyContent = "space-between"; // 两端对齐,元素之间间隔相等
} else if (obj.ja) {
el.style.justifyContent = "space-around"; // 元素两侧间隔相等,故元素之间的间隔比元素到边框的距离大一倍
}
// align-item
if (obj.as) {
el.style.alignItems = "flex-start"; // 垂直布局时左对齐,水平布局时上对齐
} else if (obj.ac) {
el.style.alignItems = "center"; // 居中
} else if (obj.ae) {
el.style.alignItems = "flex-end"; // 垂直布局时右对齐,水平布局时下对齐
} else if (obj.ab) {
el.style.alignItems = "baseline"; // 元素的第一行文字的基线对齐。
}
}
})
效果:
元素隐藏
html
<div v-hide></div>
directive
import Vue from 'vue'
// 使用方式:v-hide="boolean"(不传默认隐藏)
Vue.directive("hide", (el, binding) => {
let flag = binding.value === undefined ? true : binding.value;
el.style.display = flag ? "none" : "";
})