国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

vue 指令之氣泡提示效果的實現代碼

2019-11-19 12:41:00
字體:
來源:轉載
供稿:網友

菜鳥學習之路

//L6zt github

自己 在造組件輪子,也就是瞎搞。

自己寫了個slider組件,想加個氣泡提示。為了復用和省事特此寫了個指令來解決。

預覽地址

項目地址 github 我叫給它胡博

效果圖片

我對指令的理解: 前不久看過 一部分vnode實現源碼,奈何資質有限...看不懂。

vnode的生命周期-----> 生成前、生成后、生成真正dom、更新 vnode、更新dom 、 銷毀。

而Vue的指令則是依賴于vnode 的生命周期, 無非也是有以上類似的鉤子。

代碼效果

指令掛A元素上,默認生成一個氣泡容器B插入到 body 里面,B 會獲取 元素 A 的位置信息 和 自己的
大小信息,經過 一些列的運算,B 元素會定位到 A 的 中間 上 位置。 當鼠標放到 A 上 B 就會顯示出來,離開就會消失。

以下代碼

氣泡指令

import { on , off , once, contains, elemOffset, position, addClass, removeClass } from '../utils/dom';import Vue from 'vue'const global = window;const doc = global.document;const top = 15;export default { name : 'jc-tips' , bind (el , binding , vnode) {  // 確定el 已經在頁面里 為了獲取el 位置信信   Vue.nextTick(() => {   const { context } = vnode;   const { expression } = binding;   // 氣泡元素根結點   const fWarpElm = doc.createElement('div');   // handleFn 氣泡里的子元素(自定義)   const handleFn = binding.expression && context[expression] || (() => '');   const createElm = handleFn();   fWarpElm.className = 'hide jc-tips-warp';   fWarpElm.appendChild(createElm);   doc.body.appendChild(fWarpElm);   // 給el 綁定元素待其他操作用   el._tipElm = fWarpElm;   el._createElm = createElm;   // 鼠標放上去的 回調函數   el._tip_hover_fn = function(e) {    // 刪除節點函數     removeClass(fWarpElm, 'hide');     fWarpElm.style.opacity = 0;     // 不加延遲 fWarpElm的大小信息 (元素大小是 0 0)---> 刪除 class 不是立即渲染     setTimeout(() => {      const offset = elemOffset(fWarpElm);      const location = position(el);      fWarpElm.style.cssText = `left: ${location.left - offset.width / 2}px; top: ${location.top - top - offset.height}px;`;      fWarpElm.style.opacity = 1;     }, 16);   };   //鼠標離開 元素 隱藏 氣泡   const handleLeave = function (e) {    fWarpElm.style.opacity = 0;    // transitionEnd 不太好應該加入兼容    once({     el,     type: 'transitionEnd',     fn: function() {      console.log('hide');      addClass(fWarpElm, 'hide');     }    })   };   el._tip_leave_fn = handleLeave;   // 解決 slider 移動結束 提示不消失   el._tip_mouse_up_fn = function (e) {    const target = e.target;    console.log(target);    if (!contains(fWarpElm, target) && el !== target) {     handleLeave(e)    }   };   on({    el,    type: 'mouseenter',    fn: el._tip_hover_fn   });   on({    el,    type: 'mouseleave',    fn: el._tip_leave_fn   });   on({    el: doc.body,    type: 'mouseup',    fn: el._tip_mouse_up_fn   })  }); } , // 氣泡的數據變化 依賴于 context[expression] 返回的值 componentUpdated(el , binding , vnode) {  const { context } = vnode;  const { expression } = binding;  const handleFn = expression && context[expression] || (() => '');  Vue.nextTick( () => {   const createNode = handleFn();   const fWarpElm = el._tipElm;   if (fWarpElm) {    fWarpElm.replaceChild(createNode, el._createElm);    el._createElm = createNode;    const offset = elemOffset(fWarpElm);    const location = position(el);    fWarpElm.style.cssText = `left: ${location.left - offset.width / 2}px; top: ${location.top - top - offset.height}px;`;   }  }) }, // 刪除 事件 unbind (el , bind , vnode) {  off({   el: dov.body,   type: 'mouseup',   fn: el._tip_mouse_up_fn  });  el = null; }}

slider 組件

<template>  <div class="jc-slider-cmp">    <section        class="slider-active-bg"        :style="{width: `${left}px`}"      >    </section>      <i          class="jc-slider-dot"          :style="{left: `${left}px`}"          ref="dot"          @mousedown="moveStart"          v-jc-tips="createNode"      >      </i>  </div></template><script> import {elemOffset, on, off, once} from "../../utils/dom"; const global = window; const doc = global.document; export default {  props: {   step: {    type: [Number],    default: 0   },   rangeEnd: {    type: [Number],    required: true   },   value: {    type: [Number],    required: true   },   minValue: {    type: [Number],    required: true   },   maxValue: {    type: [Number],    required: true   }  },  data () {   return {    startX: null,    width: null,    curValue: 0,    curStep: 0,    left: 0,    tempLeft: 0   }  },  computed: {   wTov () {    let step = this.step;    let width = this.width;    let rangeEnd = this.rangeEnd;    if (width) {     if (step) {      return width / (rangeEnd / step)     }     return width / rangeEnd    }    return null   },   postValue () {    let value = null;    if (this.step) {     value = this.step * this.curStep;    } else {     value = this.left / this.wTov;    }    return value;   }  },  watch: {    value: {     handler (value) {      this.$nextTick(() => {       let step = this.step;       let wTov = this.wTov;       if (step) {        this.left = value / step * wTov;       } else {        this.left = value * wTov;       }      })     },     immediate: true    }  },  methods: {   moveStart (e) {    e.preventDefault();    const body = window.document.body;    const _this = this;    this.startX = e.pageX;    this.tempLeft = this.left;    on({     el: body,     type: 'mousemove',     fn: this.moving    });    once({     el: body,     type: 'mouseup',     fn: function() {      console.log('end');      _this.$emit('input', _this.postValue);      off({       el: body,       type: 'mousemove',       fn: _this.moving      })     }    })   },   moving(e) {    let curX = e.pageX;    let step = this.step;    let rangeEnd = this.rangeEnd;    let width = this.width;    let tempLeft = this.tempLeft;    let startX = this.startX;    let wTov = this.wTov;    if (step !== 0) {     let all = parseInt(rangeEnd / step);     let curStep = (tempLeft + curX - startX) / wTov;     curStep > all && (curStep = all);     curStep < 0 && (curStep = 0);     curStep = Math.round(curStep);     this.curStep = curStep;     this.left = curStep * wTov;    } else {     let left = tempLeft + curX - startX;     left < 0 && (left = 0);     left > width && (left = width);     this.left = left;    }   },   createNode () {    const fElem = document.createElement('i');    const textNode = document.createTextNode(this.postValue.toFixed(2));    fElem.appendChild(textNode);    return fElem;   }  },  mounted () {   this.width = elemOffset(this.$el).width;  } };</script><style lang="scss">  .jc-slider-cmp {    position: relative;    display: inline-block;    width: 100%;    border-radius: 4px;    height: 8px;    background: #ccc;    .jc-slider-dot {      position: absolute;      display: inline-block;      width: 15px;      height: 15px;      border-radius: 50%;      left: 0;      top: 50%;      transform: translate(-50%, -50%);      background: #333;      cursor: pointer;    }    .slider-active-bg {      position: relative;      height: 100%;      border-radius: 4px;      background: red;    }  }</style>../utils/domconst global = window;export const on = ({el, type, fn}) => {     if (typeof global) {       if (global.addEventListener) {         el.addEventListener(type, fn, false)      } else {         el.attachEvent(`on${type}`, fn)      }     }  };  export const off = ({el, type, fn}) => {    if (typeof global) {      if (global.removeEventListener) {        el.removeEventListener(type, fn)      } else {        el.detachEvent(`on${type}`, fn)      }    }  };  export const once = ({el, type, fn}) => {    const hyFn = (event) => {      try {        fn(event)      }       finally {        off({el, type, fn: hyFn})      }    }    on({el, type, fn: hyFn})  };  // 最后一個  export const fbTwice = ({fn, time = 300}) => {    let [cTime, k] = [null, null]    // 獲取當前時間    const getTime = () => new Date().getTime()    // 混合函數    const hyFn = () => {      const ags = argments      return () => {        clearTimeout(k)        k = cTime = null        fn(...ags)      }    };    return () => {      if (cTime == null) {        k = setTimeout(hyFn(...arguments), time)        cTime = getTime()      } else {        if ( getTime() - cTime < 0) {          // 清除之前的函數堆 ---- 重新記錄          clearTimeout(k)          k = null          cTime = getTime()          k = setTimeout(hyFn(...arguments), time)        }      }}  };  export const contains = function(parentNode, childNode) {    if (parentNode.contains) {      return parentNode !== childNode && parentNode.contains(childNode)    } else {      // https://developer.mozilla.org/zh-CN/docs/Web/API/Node/compareDocumentPosition      return (parentNode.compareDocumentPosition(childNode) === 16)    }  };  export const addClass = function (el, className) {    if (typeof el !== "object") {      return null    }    let classList = el['className']    classList = classList === '' ? [] : classList.split(//s+/)    if (classList.indexOf(className) === -1) {      classList.push(className)      el.className = classList.join(' ')    }  };  export const removeClass = function (el, className) {    let classList = el['className']    classList = classList === '' ? [] : classList.split(//s+/)    classList = classList.filter(item => {      return item !== className    })    el.className =   classList.join(' ')  };  export const delay = ({fn, time}) => {    let oT = null    let k = null    return () => {      // 當前時間      let cT = new Date().getTime()      const fixFn = () => {        k = oT = null        fn()      }      if (k === null) {        oT = cT        k = setTimeout(fixFn, time)        return      }      if (cT - oT < time) {        oT = cT        clearTimeout(k)        k = setTimeout(fixFn, time)      }    }  };  export const position = (son, parent = global.document.body) => {    let top = 0;    let left = 0;    let offsetParent = son;    while (offsetParent !== parent) {      let dx = offsetParent.offsetLeft;      let dy = offsetParent.offsetTop;      let old = offsetParent;      if (dx === null) {        return {          flag: false        }      }      left += dx;      top += dy;   offsetParent = offsetParent.offsetParent;      if (offsetParent === null && old !== global.document.body) {        return {          flag: false        }      }    }    return {      flag: true,      top,      left    }  };  export const getElem = (filter) => {    return Array.from(global.document.querySelectorAll(filter));  };  export const elemOffset = (elem) => {    return {      width: elem.offsetWidth,      height: elem.offsetHeight    }  };

總結

以上所述是小編給大家介紹的vue 指令之氣泡提示效果的實現代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 藁城市| 宁阳县| 庆安县| 黔西县| 沙雅县| 乐都县| 板桥市| 阿合奇县| 宁南县| 正定县| 慈溪市| 南汇区| 永定县| 南丹县| 凌云县| 安图县| 兰坪| 牙克石市| 星子县| 康马县| 新宁县| 酒泉市| 甘谷县| 邓州市| 光泽县| 衡水市| 合山市| 三河市| 大邑县| 南通市| 邛崃市| 专栏| 青冈县| 青田县| 文登市| 张掖市| 聂拉木县| 玉田县| 汝州市| 望谟县| 黎平县|