предисловие
На прошлой неделе я поделился с вами тем, как использовать пользовательскую команду Vue для реализации пользовательского контекстного меню браузера. Всем показалось, что это очень интересно. На этот раз я превратил его в плагин и загрузил в репозиторий npm.
В процессе создания этого плагина я наступил на множество ям. В этой статье я поделюсь с вами своими идеями реализации и процессом. Заинтересованные разработчики могут прочитать эту статью.
Строительство окружающей среды
Сначала я использовал команду tsc машинописного текста непосредственно для упаковки, но я использовал vue и scss в своем плагине и обнаружил, что для упаковки этих файлов мне нужно настроить веб-пакет самостоятельно.
Я помню давным-давно, когда я использовал Vue CLI 2.x для создания проекта, я мог выбрать, будет ли создаваемый проект плагином или веб-проектом.Теперь я использую Vue CLI 4.x, и я не не вижу эту опцию, когда я создал проект.
Итак, по счастливой случайности я зашел на официальный сайт Vue CLI, чтобы найти волну, и действительно нашел ее.build
Есть командаtarget
вариант, вы можете упаковать его в плагин, его конкретное использование:vue-cli-service build.
Поскольку Vue CLI предоставляет готовое решение, используйте то, что оно предоставляет.
Создать проект
- Перейдите в каталог вашего проекта в терминале и используйте
create
команда для созданияvue-right-click-menu-next
проект
vue create vue-right-click-menu-next
- На следующем шаге выберите пользовательскую конфигурацию, выберите vue3, node-sass, eslint+prettier, напечатайте эти параметры.
Настроить зависимости
После создания проекта мы удаляем вещи, созданные при инициализации CLI, а затем модифицируем содержимое package.json.
В package.json CLI по умолчанию помещаетvue
а такжеcore-js
помещатьdependencies
Кроме того, на плагины, которые мы разрабатываем, должны ссылаться другие разработчики.Если пакет Vue включен в наш упакованный продукт, это может вызвать различные проблемы.Например, пользователи могут создать два пакета во время выполнения после представления нашего пакета. экземпляр не используется, поэтому его нельзя помещать в зависимости в package.json плагина vue, а нужно помещать вpeerDependencies
, указывающее, что соответствующий пакет будет импортирован из других пакетов реферера, а не напрямую импортирован в этот пакет.
- Добавьте следующий код в package.json, чтобы удалить зависимости в исходных зависимостях.
"peerDependencies": {
"core-js": "^3.6.5",
"vue": "^3.0.0"
}
- Добавьте зависимости, связанные со спецификацией git commit, в devDependencies.
{
"@commitlint/cli": "^11.0.0",
"@commitlint/config-angular": "^11.0.0",
"commitizen": "^4.2.2",
"cz-conventional-changelog": "^3.3.0",
"husky": "^4.3.0",
}
- Добавьте config и husky, чтобы настроить журнал изменений для генерации адресов и заставить редакторов отправлять код в соответствии с нашими определенными спецификациями.
{
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}
- Наконец, добавьте команду отправки и команду для создания журнала изменений в скрипте.
{
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"commit": "git-cz"
}
Настроить команды упаковки
Зависит отДокументацияВидно, что черезvue-cli-service build --target lib --name myLib [entry]
команда для создания одной записи в виде библиотеки.
Затем мы можем добавить команду сборки в тег скрипта package.json для выполнения упаковки плагина.Код выглядит следующим образом.
- Имя упакованного файла vueRightMenuPlugin
- Входной файл плагина src/main.ts
{
"build": "vue-cli-service build --target lib --name vueRightMenuPlugin src/main.ts",
}
Поскольку в нашем плагине включен машинописный текст, использование его упаковки по умолчанию не поможет нам сгенерировать файл объявления ts. Проект разработчика, использующий наш плагин, может включить машинописный текст, и при ссылке на плагин будет сообщено об ошибке. Файл объявления не существует, поэтому нам нужно сделать следующее дополнительно:
- существует
tsconfig.json
Добавьте следующий код в z, и файл конфигурации будет автоматически сгенерирован в указанном месте проекта при упаковке.
{
"declaration": true,// 是否生成声明文件
"declarationDir": "dist/lib",// 声明文件打包的位置
}
- Создайте
vue.config.js
файл, чтобы отключить некоторые связанные конфигурации для параллельной упаковки.
module.exports = {
chainWebpack: config => {
if (process.env.NODE_ENV === "production") {
config.module.rule("ts").uses.delete("cache-loader");
config.module
.rule("ts")
.use("ts-loader")
.loader("ts-loader")
.tap(opts => {
opts.transpileOnly = false;
opts.happyPackMode = false;
return opts;
});
}
},
parallel: false
};
После выполнения вышеуказанных операций мы можем автоматически сгенерировать файл объявления при запуске команды упаковки.
заставить css встроенный
Когда я закончил разработку плагина, я обнаружил, что стиль компонента, на который я ссылался, был потерян во время теста.Я долго искал проблему и, наконец, нашел проблему в документации CLI.У него есть свойство css.extract , который используется для настройки включения. Стиль css извлекается в отдельный файл. По умолчанию: находится в производственной среде.true
, в среде разработки естьfalse
, когда мы упаковываем его, по умолчанию онtrue
, пользователю необходимо импортировать этот файл стиля отдельно.
Мы можем сделать это, вручную установив его вfalse
, пусть он использует встроенные стили при упаковке, чтобы можно было решить проблему инвалидации стиля, мы находимся вvue.config.js
Добавьте в него следующий код.
module.exports = {
// 强制css内联
css: { extract: false }
}
Добавить описание библиотеки
После выполнения вышеперечисленных операций мы завершили настройку, связанную с упаковкой, далее добавим описание библиотеки в package.json, чтобы npm смог корректно идентифицировать наш плагин.
- имя имя плагина
- версия номер версии
- краткое описание плагина описания
- личное есть личное
- Расположение входного файла основной библиотеки (упакованный входной файл)
- Расположение файла объявления для библиотеки типов
- издатель библиотеки издатель
- информация о репозитории
- ключевые слова ключевые слова, ключевые слова, которые совпадают, когда npm находит пакеты
- Автор библиотеки
- соблюдать лицензионное соглашение библиотеки с открытым исходным кодом
- ошибки адрес обратной связи об ошибках
- Домашняя страница домашней библиотеки
{
"name": "vue-right-click-menu-next",
"version": "1.0.0",
"description": "支持vue3的右键菜单插件",
"private": false,
"main": "dist/vueRightMenuPlugin.common.js",
"types": "dist/lib/main.d.ts",
"publisher": "magicalprogrammer@qq.com",
"repository": {
"type": "git",
"url": "git+https://github.com/likaia/vue-right-click-menu-next.git"
},
"keywords": [
"vuejs",
"vue3",
"vue",
"rightMenu",
"右键菜单",
"vueRightMenu"
],
"author": "likaia",
"license": "MIT",
"bugs": {
"url": "https://github.com/likaia/vue-right-click-menu-next/issues"
},
"homepage": "https://github.com/likaia/vue-right-click-menu-next#readme",
}
Чтобы получить полный файл конфигурации, перейдите по ссылке:package.json
Реализовать идеи
Предыдущая статьяНаша идея реализации состоит в том, чтобы vuex выполнял глобальное управление состоянием и контролировал отображение и скрытие контекстного меню. На этот раз мы хотим сделать его подключаемым модулем. Если мы снова будем использовать vuex, те, кто использует наш подключаемый модуль надо ввести vuex, тут немного не к месту.
Компоненты дисплея
Немного подумав, я пришел к следующим идеям:
- Сделайте контекстное меню компонентом, через
props
Передать значения компонентам. - использовать
createApp
загрузить компонент, передать значения компоненту, создать контейнер компонента - Создайте элемент div и смонтируйте контейнер компонента прямо сейчас в этом элементе div.
уничтожить компонент
Проделав вышеперечисленные операции, мы поняли, что меню правого клика отображается до указанной позиции, но как его скрыть, после некоторых размышлений, я пришел к следующим идеям:
- Реализация вышеуказанного компонента загрузки инкапсулирована в функцию, а созданный элемент div используется в качестве возвращаемого значения.
- Глобально объявить переменную в плагине
menuVM
, по умолчанию объявлено как null - Когда внутри инструкции запускается событие щелчка правой кнопкой мыши, вызывается инкапсулированная нами функция, используя
menuVM
чтобы получить его возвращаемое значение - На этом этапе мы создаем глобальный прослушиватель событий щелчка, если
menuVM
не равен нулю, мы удаляем элемент - Когда срабатывает событие правой кнопки, если
menuVM
Если он не нулевой, значит, контекстное меню, которое он открыл в прошлый раз, не закрыто, поэтому будет проблема, поэтому нам также нужно удалить его из тела.
Процесс реализации
Проанализировав идею реализации, приступим к ее реализации.
Создайте компонент контекстного меню
Создайте папку компонентов в src проекта и создайте ее в папкеright-menu.vue
Мы не будем размещать здесь файл, стиль и содержимое компонента. Здесь мы будем размещать параметры, которые должен передать компонент. Пожалуйста, перейдите к полному коду:right-menu.vue)
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "right-menu",
props: {
rightMenuStatus: String,
rightMenuTop: String,
rightMenuLeft: String,
rightMenuList: Array
}
});
</script>
Функция компонента монтирования пакета
Мы можем использовать vue3createApp
Чтобы загрузить компонент, передать ему значение, а затем смонтировать его на узле dom, код выглядит следующим образом:
/**
* 将组件挂在到节点上
* @param comp 需要挂载的组件
* @param prop 向组件传的参数
*/
const creatComp = function(comp: Component, prop: rightMenuAttribute) {
// 创建组件
const app = createApp(comp, {
...prop
});
// 创建一个div元素
const divEle = document.createElement("div");
// 将创建的div元素挂载追加至body里
document.body.appendChild(divEle);
// 将组件挂载至刚才创建的div中
app.mount(divEle);
// 返回挂载的元素,便于操作
return divEle;
};
Зарегистрируйте директивы в меню установки и отображения
Далее прописываем vue-инструкцию в методе install плагинаrightClick
, перехватить его событие щелчка правой кнопкой мыши, получить параметры, переданные компонентом, смонтировать компонент и отобразить контекстное меню. код показывает, как показано ниже:
install(app: App): void {
// 创建指令
app.directive("rightClick", (el, binding): boolean | void => {
// 指令绑定元素元素是否存在判断
if (el == null) {
throw "右键指令错误:元素未绑定";
}
el.oncontextmenu = function(e: MouseEvent) {
if (menuVM != null) {
// 销毁上次触发的右键菜单DOM
document.body.removeChild(menuVM);
menuVM = null;
}
const textArray = binding.value.text;
const handlerObj = binding.value.handler;
// 菜单选项与事件处理函数是否存在
if (textArray == null || handlerObj == null) {
throw "右键菜单内容与事件处理函数为必传项";
}
// 事件处理数组
const handlerArray = [];
// 处理好的右键菜单
const menuList = [];
// 将事件处理函数放入数组中
for (const key in handlerObj) {
handlerArray.push(handlerObj[key]);
}
if (textArray.length !== handlerArray.length) {
// 文本数量与事件处理不对等
throw "右键菜单的每个选项,都必须有它的事件处理函数";
}
// 追加右键菜单数据
for (let i = 0; i < textArray.length; i++) {
// 右键菜单对象, 添加名称
const menuObj: rightMenuObjType = {
text: textArray[i],
handler: handlerArray[i],
id: i + 1
};
menuList.push(menuObj);
}
// 鼠标点的坐标
const oX = e.clientX;
const oY = e.clientY;
// 动态挂载组件,显示右键菜单
menuVM = creatComp(rightMenu, {
rightMenuStatus: "block",
rightMenuTop: oY + "px",
rightMenuLeft: oX + "px",
rightMenuList: menuList
});
return false;
};
});
}
Создать компонент уничтожения слушателя
Когда пользователь щелкает контекстное меню, нам нужно уничтожить компонент и скрыть его, поэтому мы создаем прослушиватель кликов на теле при установке плагина, а затем удаляем смонтированный компонент.Код выглядит следующим образом:
install(app: App): void {
// 监听全局点击,销毁右键菜单dom
document.body.addEventListener("click", () => {
if (menuVM != null) {
// 销毁右键菜单DOM
document.body.removeChild(menuVM);
menuVM = null;
}
});
}
Пожалуйста, перейдите к полному коду:main.ts)
Опубликовать плагин
После выполнения вышеуказанных операций наш плагин разработан и может быть упакован и опубликован в репозиторий npm.
Терминал выполняет следующую команду:
npm publish --access public
Плагин успешно опубликован:vue-right-click-menu-next
Совместимость с Vue2.x
Плагин не совместим с Vue2.x, из-за нового синтаксиса Vue3 при создании приложения я изначально хотел использовать расширение Vue2.x для монтирования компонентов, но обнаружил, что Vue3 отказался от этого синтаксиса.
Это заставило меня написать два набора плагинов и поддерживать два плагина.
Разницы в логическом уровне плагина нет, отличается только способ написания смонтированного компонента.В Vue2.x требуется следующий способ написания:
/**
* 将组件挂在到节点上
* @param comp 需要挂载的组件
* @param prop 向组件传的参数
*/
const creatComp = function(comp, prop) {
// 创建组件
const app = Vue.extend(comp);
// 创建一个div元素
const divEle = document.createElement("div");
// 将创建的div元素挂载追加至body里
document.body.appendChild(divEle);
// 将组件挂载至刚才创建的div中, 使用propsData进行传参
new app({
propsData: {
...prop
}
}).$mount(divEle);
// 返回挂载的元素,便于操作
return divEle;
};
Адрес плагина:vue-right-click-menu
адрес проекта
Адрес кода плагина, разработанного в этой статье:vue-right-click-menu | vue-right-click-menu-next)
Адрес онлайн-опыта:chat-system
напиши в конце
-
Если в статье есть ошибки, исправьте их в комментариях, если статья вам поможет, ставьте лайк и подписывайтесь 😊
-
Эта статья была впервые опубликована на Наггетс, перепечатка без разрешения запрещена 💌