中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么實現vue2下拉菜單dropdown組件

發布時間:2022-08-24 16:38:42 來源:億速云 閱讀:379 作者:iii 欄目:開發技術

本篇內容介紹了“怎么實現vue2下拉菜單dropdown組件”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    概述

    一般后臺項目結合分頁組件用到這個dropdown組件,用來做顯示分頁條數,其他用到這個組件的地方倒不是很多,其實現思路和select組件有那么些相似,現記錄下這個組件的實現。

    實現原理

    需要注意以下幾點:

    組件分為兩部分:

    • 供我們點擊的文字,按鈕,超鏈接等等(當成插槽供用戶提供)

    • 下拉菜單項(支持邊框,禁用等)

    使用該組件應當提供的事件應該是點擊item項,然后將對應的item的對應value暴露出來,供用戶使用。

    組件菜單項的顯示隱藏需要過渡動畫。

    默認菜單項方向向下,當下方可視區的高度不足以容納下拉菜單的高度的時候,自動讓菜單方向向上。

    具體實現

    目錄結構

    怎么實現vue2下拉菜單dropdown組件

    emitter.js

    這個在之前的組件實現過程中介紹過這個文件,主要是為了解決跨多層級父子組件之前數據通信的,本質上實現原理為發布訂閱模式。

    /**
     * @Description 由于涉及到跨組件之間通信,因此我們只有自己實現發布訂閱的模式,來實現組件之間通信,靈感主要來源于element-ui組件庫源碼中跨層級父子組件通信方案,本質上也是發布訂閱和$emit和$on
     * @param { String } componentName 組件名
     * @param { String } eventName 事件名
     * @param { argument } params 參數
     **/
    // 廣播通知事件
    function _broadcast(componentName, eventName, params) {
      // 遍歷當前組件的子組件
      this.$children.forEach(function (child) {
        // 取出componentName,組件options上面可以自己配置
        var name = child.$options.componentName;
        // 如果找到了需要通知的組件名,觸發組件上面的$eimit方法,觸發自定義事件
        if (name === componentName) {
          child.$emit.apply(child, [eventName].concat(params));
        } else {
          // 沒找到,遞歸往下找
          _broadcast.apply(child, [componentName, eventName].concat([params]));
        }
      });
    }
    const emiiter = {
      methods: {
        // 派發事件(通知父組件)
        dispatch(componentName, eventName, params) {
          var parent = this.$parent || this.$root;
          var name = parent.$options.componentName;
          // 循環往上層父組件,知道知道組件名和需要觸發的組件名相同即可,然后觸發對應組件的事件
          while (parent && (!name || name !== componentName)) {
            parent = parent.$parent;
            if (parent) {
              name = parent.$options.componentName;
            }
          }
          if (parent) {
            parent.$emit.apply(parent, [eventName].concat(params));
          }
        },
        // 廣播事件(通知子組件)
        broadcast(componentName, eventName, params) {
          _broadcast.call(this, componentName, eventName, params);
        },
      },
    };
    export default emiiter;

    MyDropdown.vue

    主要暴露給用戶使用的組件

    <template>
      <div
        class="my-dropdown"
        @click.stop="trigger == 'click' ? (showMenu = !showMenu) : ''"
        @mouseenter="trigger == 'hover' ? (showMenu = true) : ''"
        @mouseleave="trigger == 'hover' ? (showMenu = false) : ''"
        ref="myDropDdown"
      >
        <div class="tip-text" ref="tipText">
          <slot></slot>
        </div>
        <slot name="list"></slot>
      </div>
    </template>
    <script>
    import emitter from "./emitter";
    export default {
      name: "MyDropdown",
      componentName: "MyDropdown",
      mixins: [emitter],
      props: {
        // 觸發顯示方式
        trigger: {
          type: String,
          default: "click",
        },
        // 下來菜單的出現位置(上方,下方)
        placement: {
          type: String,
          default: "bottom",
          validator: function (value) {
            // 這個值必須匹配下列字符串中的一個
            return ["bottom", "top"].includes(value);
          },
        },
      },
      data() {
        return {
        //控制菜單是否顯示
          showMenu: false,
        };
      },
      mounted() {
          //初始化自定義事件
        this.initEvent();
      },
      methods: {
        // 初始化
        initEvent() {
        //訂閱當item點擊的時候,發布on-click事件,告知外部
          this.$on("item-click", (params) => {
            this.$emit("on-click", params);
            this.showMenu = false;
          });
          //空白點擊要隱藏菜單,需要執行的函數需要綁定this指向
          this.handleEmptyDomElementClickBindThis =
            this.handleEmptyDomElementClick.bind(this);
          window.addEventListener("click", this.handleEmptyDomElementClickBindThis);
        },
        // 處理空白區域點擊,隱藏菜單列表
        handleEmptyDomElementClick(e) {
          if (!Array.from(this.$refs.myDropDdown.childNodes).includes(e.target)) {
            this.showMenu = false;
          }
        },
      },
      beforeDestroy() {
        // 移除window上面的事件
        window.removeEventListener(this.handleEmptyDomElementClickBindThis);
      },
      watch: {
      //變化的時候,通知子組件隱藏菜單列表
        showMenu() {
          this.broadcast("MyDropdownMenu", "set-menu-status", this.showMenu);
        },
      },
    };
    </script>
    <style lang="less">
    .my-dropdown {
      position: relative;
    }
    </style>

    MyDropdownMenu.vue

    主要暴露給用戶使用的組件,菜單列表組件

    <template>
    <!-- 涉及到高度,位移,過渡使用js鉤子函數的方式比較好處理些 -->
      <transition
        @before-enter="beforeEnter"
        @enter="enter"
        @leave="leave"
        v-bind:css="false"
      >
        <div class="my-dropdown-menu" v-if="showMeune" ref="myDroupdownMenu">
          <slot></slot>
        </div>
      </transition>
    </template>
    <script>
    import emitter from "./emitter";
    export default {
      name: "MyDropdownMenu",
      componentName: "MyDropdownMenu",
      mixins: [emitter],
      data() {
        return {
          showMeune: false,
          timer: null,
        };
      },
      mounted() {
        this.$on("set-menu-status", (status) => {
          this.showMeune = status;
        });
      },
      methods: {
      //進入前,初始化需要過渡的屬性
        beforeEnter: function (el) {
          // 初始化
          el.style.opacity = 0;
          el.style.transform = "scaleY(0)";
          el.style.transformOrigin = "top center";
        },
      //dom進入
        enter: function (el, done) {
        //獲取文檔可視區高度
          const htmlClientHeight = document.documentElement.clientHeight;
          //菜單列表相對于父元素的top偏移量
          const offsetTop = el.offsetTop;
          const scrollHeight = el.scrollHeight;
          //獲取當前元素和可視區的一些長度(top,left,bottom等)
          const { bottom } = el.getBoundingClientRect();
          // 說明底部高度不夠顯示菜單了,這時候我們需要調整菜單朝上面顯示
          if (htmlClientHeight - bottom < scrollHeight) {
            el.style.transformOrigin = "bottom center";
            el.style.top = -(scrollHeight + 20) + "px";
          } else {
          //查看是否placement屬性,是的話我們主動處理
            if (this.$parent.placement == "top") {
              el.style.transformOrigin = "bottom center";
              el.style.top = -(scrollHeight + 20) + "px";
            } else {
              el.style.top = offsetTop + "px";
            }
          }
          el.style.transform = "scaleY(1)";
          el.style.opacity = 1;
        //根據官網事例,必須在enter和leave里面調用done函數,不然過渡動畫不生效(切記)
          done();
        },
        //dom元素離開 
        leave: function (el, done) {
          el.style.transform = "scaleY(0)";
          el.style.opacity = 0;
          clearTimeout(this.timer);
          this.timer = setTimeout(() => {
          //根據官網事例,必須在enter和leave里面調用done函數,不然過渡動畫不生效(切記)
            done();
          }, 250);
        },
      },
    };
    </script>
    <style lang="less">
    .my-dropdown-menu {
      min-width: 100px;
      max-height: 200px;
      overflow: auto;
      margin: 5px 0;
      padding: 5px 0;
      background-color: #fff;
      box-sizing: border-box;
      border-radius: 4px;
      box-shadow: 0 1px 6px rgb(0 0 0 / 20%);
      z-index: 900;
      transform-origin: top center;
      position: absolute;
      transition: transform 0.25s ease, opacity 0.25s ease;
    }
    </style>

    MyDropdownItem.vue

    主要暴露給用戶使用的組件,菜單列表項組件,組件內容很簡單,主要就是展示item數據和綁定點擊事件。

    <template>
      <div
        :class="[
          'my-dropdownItem',
          divided ? 'my-dropdownItem-divided' : '',
          disabled ? 'my-dropdownItem-disabled' : '',
        ]"
        @click.stop="handleItemClick"
      >
        <slot></slot>
      </div>
    </template>
    <script>
    import emitter from "./emitter";
    export default {
      name: "MyDropdownItem",
      componentName: "MyDropdownItem",
      mixins: [emitter],
      props: {
        divided: {
          type: Boolean,
          default: false,
        },
        disabled: {
          type: Boolean,
          default: false,
        },
        name: {
          type: String,
          default: "",
        },
      },
      data() {
        return {};
      },
      methods: {
        handleItemClick() {
          if (this.disabled) return;
          // item項點擊通知dropdown組件派發到外部的自定義事件
          this.dispatch("MyDropdown", "item-click", this.name);
        },
      },
    };
    </script>
    <style lang="less">
    .my-dropdownItem {
      margin: 0;
      line-height: normal;
      padding: 7px 16px;
      clear: both;
      color: #515a6e;
      font-size: 14px !important;
      white-space: nowrap;
      list-style: none;
      cursor: pointer;
      transition: background 0.2s ease-in-out;
      &:hover {
        background: #f3f3f3;
      }
    }
    .my-dropdownItem-divided {
      border-bottom: 1px solid #eee;
    }
    .my-dropdownItem-disabled {
      color: #cacdd2;
      cursor: not-allowed;
      &:hover {
        background: #fff;
      }
    }
    </style>

    “怎么實現vue2下拉菜單dropdown組件”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    比如县| 宁乡县| 浦城县| 芮城县| 湘潭县| 潜山县| 藁城市| 秦皇岛市| 定州市| 祁连县| 梁平县| 鹤峰县| 蓬莱市| 岳普湖县| 安义县| 泽库县| 钟祥市| 凤冈县| 达拉特旗| 汶上县| 贡嘎县| 阿瓦提县| 阳原县| 贵港市| 辉县市| 商河县| 明溪县| 克东县| 濉溪县| 时尚| 巴塘县| 丰顺县| 金堂县| 莱阳市| 长汀县| 马公市| 宣汉县| 大丰市| 卓资县| 驻马店市| 通道|