vue-自定义属性

懒加载

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}`;
   }
})

效果:
vue-自定义属性

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";         // 元素的第一行文字的基线对齐。
      }
   }
})

效果:
vue-自定义属性

元素隐藏

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" : "";
})
上一篇:vue3 - 可复用 & 组合 - 自定义指令(未完)


下一篇:Vue自定义指令和路由