Используйте пользовательскую директиву Vue для реализации контекстного меню.

Vue.js
Используйте пользовательскую директиву Vue для реализации контекстного меню.

предисловие

При щелчке правой кнопкой мыши в браузере будет меню по умолчанию. В моем проекте с открытым исходным кодом необходимо настроить контекстное меню. Я нашел соответствующие пакеты в библиотеке npm и обнаружил, что все они реализованы в виде компонентов.Я чувствую, что этот подход слишком громоздкий.

Итак, я задался вопросом, могу ли я связать его с таким элементом, как встроенные инструкции Vue, и щелкнуть правой кнопкой мыши по этому элементу, чтобы отобразить контекстное меню, что было бы намного удобнее.

После прочтения пользовательского документа с инструкциями Vue, после долгих метаний, я наконец осуществил свою идею. В этой статье я поделюсь с вами своими идеями реализации и процессом. Заинтересованные разработчики могут прочитать эту статью.

Реализовать идеи

В Vue есть много встроенных директив, например:v-if,v-for,v-model, в дополнение к этим встроенным директивам, это также позволяет нашим разработчикам регистрировать свои собственные директивы для достижения желаемого эффекта Разработчики, которые не знакомы с пользовательскими директивами Vue, могут сначала просмотреть документацию:пользовательская директива.

Далее позвольте мне рассказать вам о моих идеях реализации:

  • Макет контекстного меню, стиль записи

  • Определите данные, необходимые для контекстного меню в vuex.

  • Зарегистрируйте директиву глобально, с именемrightClick

  • Перехватить связанный элементoncontextmenuсобытие, которое обрабатывает значение, переданное компонентом

  • Обновите данные контекстного меню в vuex, чтобы вызвать отображение контекстного меню.

Процесс реализации

Далее я поделюсь с вами своим процессом реализации.

Стиль макета правой кнопкой мыши

Давайте сначала посмотрим, какие данные нужны этому компоненту, чтобы он отображался там, где находится мышь.

  • Его явное и скрытое состояние, а именно: элемент cssdisplayАтрибуты
  • его местоположение, то есть: элемент cssleft,topАтрибуты
  • Его текстовые данные, то есть содержимое, которое должно отображаться в контекстном меню, отображаются черезv-forоказывать
  • Его функция обработки событий, а именно: обработка событий, которая будет выполняться при выборе параметра в контекстном меню.

Находим общий компонент в проекте, чтобы убедиться, что этот компонент будет рендериться, в компонентеtemplateДобавьте в него следующий код.

    <!--右键菜单-->
    <div
      id="rightMenuDom"
      class="right-menu"
      :style="{
        display: rightMenuStatus,
        top: rightMenuTop,
        left: rightMenuLeft
      }"
    >
      <ul>
        <!--分为2组渲染-->
        <li>
          <span
            v-for="item in rightMenuList"
            :key="item.id"
            v-show="item.id <= 3"
            @click="item.handler"
            >{{ item.text }}
          </span>
        </li>
        <li>
          <span
            v-for="item in rightMenuList"
            :key="item.id"
            v-show="item.id > 3"
            @click="item.handler"
            >{{ item.text }}
          </span>
        </li>
      </ul>
    </div>
  </div>

Впоследствии в компонентеmountedДобавьте глобальный прослушиватель событий щелчка в жизненном цикле, цель которого состоит в том, чтобы скрыть контекстное меню после щелчка в любом месте.

  mounted() {
    // 监听全局点击事件
    document.addEventListener("click", () => {
      // 隐藏右键菜单
      this.$store.commit("updateRightMenuStatus", {
        status: "none",
        left: "0px",
        top: "0px"
      });
    });
  }

Далее в компонентеcomputedПолучите данные, определенные в Vuex, для рендеринга контекстного меню.

  computed: {
    // 右键菜单显隐状态
    rightMenuStatus(): string {
      return this.$store.state.rightMenu.status;
    },
    // 右键菜单距离浏览器顶部高度
    rightMenuTop(): string {
      return this.$store.state.rightMenu.top;
    },
    // 右键菜单距离浏览器左边长度
    rightMenuLeft(): string {
      return this.$store.state.rightMenu.left;
    },
    // 右键菜单列表内容
    rightMenuList(): [] {
      return this.$store.state.rightMenu.list;
    }
  }

Наконец, напишите для него стили css.

// 右键菜单样式
  .right-menu {
    position: fixed;
    left: 0;
    top: 0;
    width: 166px;
    height: auto;
    background-color: rgb(242, 242, 242);
    border: solid 1px #C2C1C2;
    box-shadow: 0 10px 10px #C2C1C2;
    display: none;
    border-radius: 5px;

    ul {
      padding: 0;
      margin: 0;
      font-size: 15px;

      li {
        list-style: none;
        box-sizing: border-box;
        padding: 6px 0;
        border-bottom: 1px solid rgb(216, 216, 217);

        &:nth-child(1) {
          padding-top: 2px;
        }

        &:nth-last-child(1) {
          border-bottom: none;
        }

        span {
          display: block;
          height: 20px;
          line-height: 20px;
          padding-left: 16px;

          &:hover {
            background-color: #0070F5;
            cursor: pointer;
            color: #FFFFFF;
          }
        }
      }
    }
  }

Определение данных в Vuex

В файле конфигурации vuex найдитеstateсвойства, добавьте следующий код.

  • statusЯвное и скрытое состояние компонента
  • topРасстояние компонента от верхней части видимой области браузера
  • leftРасстояние от левого края видимой области браузера
  • listТекстовые данные, необходимые компоненту и соответствующему обработчику событий.
rightMenu: {
  status: "none",
  top: "0px",
  left: "0px",
  list: []
}

затем вmutationsДобавьте метод для обновления данных в .

// 更新右键菜单数据
updateRightMenuStatus(state, menuObj: rightMenuAttribute) {
  state.rightMenu.status = menuObj.status;
  state.rightMenu.top = menuObj.top;
  state.rightMenu.left = menuObj.left;
  state.rightMenu.list = menuObj.list;
}

Зарегистрировать глобальную директиву

Наш входной файл в vue:main.ts, зарегистрировать глобальную директивуrightClick.

  • elЭлемент, который связывает директиву для нас
  • bindingСодержит параметры, переданные командой
app.directive("rightClick", (el, binding) => {
  
});

Перехватывать параметры инструкции обработки события щелчка правой кнопкой мыши

Выше мы зарегистрировали глобальную инструкцию, нам нужно переписать ее событие щелчка для элемента, привязанного к инструкции внутри ее функции, и обработать переданные инструкцией параметры.

  • поместить объекты события в массив
  • Поместите текстовые данные каждого контекстного меню и соответствующую функцию обработки времени в массив json.
  • Чтобы получить позицию щелчка мыши, используйтеcommitОбновите соответствующие данные в Vuex и отобразите страницу.
  el.oncontextmenu = function(e: MouseEvent) {
    const textArray = binding.value.text;
    const handlerObj = binding.value.handler;
    // 事件处理数组
    const handlerArray = [];
    // 处理好的右键菜单
    const menuList = [];
    // 将事件处理函数放入数组中
    for (const key in handlerObj) {
      handlerArray.push(handlerObj[key]);
    }
    // 追加右键菜单数据
    for (let i = 0; i < textArray.length; i++) {
      // 右键菜单对象, 添加名称
      const menuObj = {
        text: textArray[i],
        handler: handlerArray[i],
        id: i + 1
      };
      menuList.push(menuObj);
    }
    // 鼠标点的坐标
    const oX = e.clientX;
    const oY = e.clientY;
    // 右键菜单出现后的位置
    store.commit("updateRightMenuStatus", {
      status: "block",
      left: oX + "px",
      top: oY + "px",
      list: menuList
    });
    return false;
  };

Использование директив в компонентах

После завершения операции мы реализовали пользовательскую команду меню прямо, а затем посмотрим, как мы используем регистр команды в сборке.

в контексте, где вы хотите связать контекстное менюhtmlдобавить элементv-right-click,Следующее:

<li
  class="row-panel"
  v-right-click="rightMenuObj"
>
</li>

в компонентеdataОпределите данные, необходимые в контекстном меню вrightMenuObj.

// 右键菜单对象,菜单内容和处理事件
rightMenuObj: {
  text: [
    "查看资料",
    "复制用户id",
    "移除该会话",
    "在联系人中查看",
    "在单聊窗口中打开",
    "会话置顶"
  ],
  handler: {
    checkingData() {
      console.log("查看资料点击事件");
    },
    copyId() {
      console.log("复制用户id点击事件");
    },
    removeItem() {
      console.log("移除会话点击事件");
    },
    showContact() {
      console.log("在联系人中查看");
    },
    showSingleChat() {
      console.log("在单聊窗口中打开");
    },
    topConversation() {
      console.log("会话置顶");
    }
  }
}

Затем мы можем запустить, чтобы увидеть эффект, как показано ниже, мы успешно достигли желаемого эффекта.

кодовый адрес

Адрес GitHub компонентов, используемых в демонстрации в этой статье, выглядит следующим образом:

msg-list.vue

main.ts

main-content.vue

main-content.scss

index.ts

напиши в конце

  • Если в статье есть ошибки, исправьте их в комментариях, если статья вам поможет, ставьте лайк и подписывайтесь 😊
  • Эта статья была впервые опубликована на Наггетс, перепечатка без разрешения запрещена 💌