学校网站建设意义,学校专业建设规划,网站建设 标准,工厂找订单哪个平台最好Vue自创插件发布到npm以及使用方法
目标#xff1a;创建my-popup-selector下拉框组件#xff0c;并发布到npm#xff0c;效果如下图#xff1a; 禁用时样式#xff1a; ①创建vue项目#xff1a; my-popup-selector ②项目目录结构截图如下#xff1a; ③在项目根目录…Vue自创插件发布到npm以及使用方法
目标创建my-popup-selector下拉框组件并发布到npm效果如下图 禁用时样式 ①创建vue项目 my-popup-selector ②项目目录结构截图如下 ③在项目根目录新建 packages/ 文件夹用于存放组件由于 packages/ 是新增的webpack无法获取编译因此需要在webpack配置文件里加上相关配置 ④在项目根目录新建 vue.config.js 配置文件并写入一下配置 module.exports {css: { // 是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态注入到 JavaScript 中的 inline 代码)。extract: false, // 生产环境下是 true开发环境下是 false},// 扩展 webpack 配置使 packages 加入编译// chainWebpack 是一个函数会接收一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改chainWebpack: config {config.module.rule(js).include.add(__dirname packages) // 注意这里需要绝对路径所以要拼接__dirname.end().use(babel).loader(babel-loader).tap(options {// 修改它的选项...return options})}
}⑤在 packages/ 文件夹下创建组件新建 vue-popup-selector/ 文件夹和 index.js 文件截图如下 ⑥在 my-popup-selector/ 文件加下新建 VueAmazingSelector.vue 组件文件和 index.js 文件截图如下 ⑦在 VueAmazingSelector.vue 中编写组件代码 templatediv classm-amazing-select :styleheight: ${height}px;div:class[m-select-wrap, {hover: !disabled, focus: showOptions, disabled: disabled}]:stylewidth: ${width - 2}px; height: ${height - 2}px;tabindex0mouseenteronInputEntermouseleaveonInputLeavebluractiveBlur !disabled ? onBlur() : e e.preventDefault()clickdisabled ? e e.preventDefault() : openSelect()div:class[u-select-input, {placeholder: !selectedName}]:styleline-height: ${height - 2}px;width: ${width - 37}px; height: ${height - 2}px;:titleselectedName{{ selectedName || placeholder }}/divsvg :class[triangle, {rotate: showOptions, show: !showClose}] viewBox64 64 896 896 data-icondown aria-hiddentrue focusablefalsepath dM884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z/path/svgsvg click.stoponClear :class[close, {show: showClose}] focusablefalse data-iconclose-circle aria-hiddentrue viewBox64 64 896 896path dM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z/path/svg/divtransition namefadedivv-showshowOptionsclassm-options-panelmouseenteronEntermouseleaveonLeave:styletop: ${height 6}px; line-height: ${height - 12}px; max-height: ${ num * (height - 2) }px; width: ${width}px;pv-for(option, index) in options :keyindex:class[u-option, {option-selected: option[label]selectedName, option-hover: !option.disabledoption[value]hoverValue, option-disabled: option.disabled }]:titleoption[label]mouseenteronHover(option[value])clickoption.disabled ? e e.preventDefault() : onChange(option[value], option[label], index){{ option[label] }}/p/div/transition/div
/template
script
export default {name: VueAmazingSelector,model: {prop: selectedValue,event: model},props: {options: { // 选项数据type: Array,default: () []},label: { // 选择器字典项的文本字段名type: String,default: label},value: { // 选择器字典项的值字段名type: String,default: value},placeholder: { // 选择框默认文字type: String,default: 请选择},disabled: { // 是否禁用下拉type: Boolean,default: false},allowClear: { // 是否支持清除type: Boolean,default: false},width: { // 选择框宽度type: Number,default: 200},height: { // 选择框高度type: Number,default: 36},num: { // 下拉面板最多能展示的下拉项数超过后滚动显示type: Number,default: 6},selectedValue: { // 当前选中的option条目v-modeltype: [Number, String],default: null}},data () {return {selectedName: null,hoverValue: null, // 鼠标悬浮项的value值activeBlur: true, // 是否激活blur事件showClose: false, // 清除按钮显隐showOptions: false // options面板}},watch: {options () {this.initSelector()console.log(options)},selectedValue () {this.initSelector()console.log(selectedValue)}},mounted () {this.initSelector()},methods: {initSelector () {if (this.selectedValue) {const target this.options.find(option option[this.value] this.selectedValue)if (target) {this.selectedName target[this.label]this.hoverValue target[this.value]} else {this.selectedName this.selectedValuethis.hoverValue null}} else {this.selectedName nullthis.hoverValue null}},onBlur () {if (this.showOptions) {this.showOptions false}},onInputEnter () {// console.log(input enter)if (this.allowClear this.selectedName) {this.showClose true}},onInputLeave () {// console.log(input leave)if (this.allowClear this.showClose) {this.showClose false}},onHover (value) {this.hoverValue value},onEnter () {this.activeBlur false},onLeave () {this.hoverValue nullthis.activeBlur true},openSelect () {this.showOptions !this.showOptionsif (!this.hoverValue this.selectedName) {const target this.options.find(option option[this.label] this.selectedName)this.hoverValue target ? target[this.value] : null}},onClear () {this.showClose falsethis.selectedName nullthis.hoverValue null},onChange (value, label, index) { // 选中下拉项后的回调if (this.selectedValue ! value) {this.selectedName labelthis.hoverValue valuethis.$emit(model, value)this.$emit(change, value, label, index)}this.showOptions false}}
}
/script
style langless scoped
themeColor: #1890ff; // 自定义主题色
P {margin: 0;
}
.m-amazing-select {position: relative;display: inline-block;font-size: 14px;font-weight: 400;color: rgba(0,0,0,.65);
}
.fade-enter-active, .fade-leave-active {transform: scaleY(1);transform-origin: 0% 0%;opacity: 1;transition: all .3s;
}
.fade-enter {transform: scaleY(0.8);transform-origin: 0% 0%;opacity: 0;
}
.fade-leave-to {transform: scaleY(1);opacity: 0;
}
.m-select-wrap {position: relative;display: inline-block;border: 1px solid #d9d9d9;border-radius: 4px;cursor: pointer;transition: all .3s cubic-bezier(.645,.045,.355,1);.u-select-input {display: block;text-align: left;margin-left: 11px;margin-right: 24px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.placeholder {color: #bfbfbf;}.triangle {position: absolute;top: 0;bottom: 0;margin: auto 0;right: 12px;width: 12px;height: 12px;fill: rgba(0,0,0,.25);opacity: 0;pointer-events: none;transition: all 0.3s ease-in-out;}.rotate {transform: rotate(180deg);-webkit-transform: rotate(180deg);}.close {opacity: 0;pointer-events: none;transition: all 0.3s ease-in-out;position: absolute;top: 0;bottom: 0;margin: auto 0;right: 12px;width: 12px;height: 12px;fill: rgba(140, 140, 140, 0.6);:hover {fill: rgba(100, 100, 100,.8);}}.show {opacity: 1;pointer-events: auto;}
}
.hover { // 悬浮时样式:hover {border-color: themeColor;}
}
.focus { // 激活时样式border-color: themeColor;box-shadow: 0 0 0 2px fade(themeColor, 20%);
}
.disabled { // 下拉禁用样式color: rgba(0,0,0,.25);background: #f5f5f5;user-select: none;cursor: not-allowed;
}
.m-options-panel {position: absolute;z-index: 999;overflow: auto;background: #FFF;padding: 4px 0;border-radius: 4px;box-shadow: 0 2px 8px rgba(0,0,0,15%);.u-option { // 下拉项默认样式text-align: left;position: relative;display: block;padding: 5px 12px;font-weight: 400;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;cursor: pointer;transition: background .3s ease;}.option-selected { // 被选中的下拉项样式font-weight: 600;background: #fafafa;}.option-hover { // 悬浮时的下拉项样式background: #e6f7ff;// background: saturate(fade(themeColor, 12%), 30%);}.option-disabled { // 禁用某个下拉选项时的样式color: rgba(0,0,0,.25);user-select: none;cursor: not-allowed;}
}
/style⑧在 my-popup-selector/index.js 中导出组件 // 引入组件
import VueAmazingSelector from ./VueAmazingSelector.vue// 为组件提供 install 安装方法供按需引入
VueAmazingSelector.install (Vue) {Vue.component(VueAmazingSelector.name, VueAmazingSelector)
}// 导出组件
export default VueAmazingSelector⑨在 packages/index.js 文件中对整个组件库进行导出 import VueAmazingSelector from ./vue-amazing-selector
// 存储组件列表
const components [VueAmazingSelector
]
/* 定义install 方法接收Vue作为参数如果使用use注册插件则所有的组件都将被注册
*/
const install function (Vue) {// 判断是否安装if (install.installed) { return }// 遍历所有组件components.map(component {Vue.component(component.name, component)})
}
// 判断是否引入文件
if (typeof window ! undefined window.Vue) {install(window.Vue)
}
export {VueAmazingSelector
}
export default {install
}在 src/main.js 中导入刚创建的组件检测是否正常可用 import VueAmazingSelector from ../packages
Vue.use(VueAmazingSelector)
// 在 App.vue 中引用并启动项目查看app.vue代码 templateVueAmazingSelector:optionsoptionslabellabelvaluevalueplaceholder请选择:disabledfalse:width160:height36:num6v-modelselectedValuechangeonChange /
/template
script
export default {name: App,data () {return {options: [{label: 北京市,value: 1},{label: 上海市上海市上海市上海市,value: 2,disabled: true},{label: 郑州市,value: 3},{label: 纽约市纽约市纽约市纽约市,value: 4},{label: 旧金山,value: 5},{label: 悉尼市,value: 6},{label: 伦敦市,value: 7},{label: 巴黎市,value: 8}],selectedValue: 1}},watch: {selectedValue (to) {console.log(selectedValue:, to)}},mounted () {setTimeout(() { // 模拟接口调用this.selectedValue 3}, 1000)},methods: {onChange (value, label, index) {console.log(item:, value, label, index)}}
}
/script⑪在 package.json 的 scripts 中添加一条编译命令 --target: 构建目标默认为应用模式。这里修改为 lib 启用库模式。
--dest : 输出目录默认 dist。这里我们改成 lib
[entry]: 最后一个参数为入口文件默认为 src/App.vue。这里我们指定编译 packages/ 组件库目录。scripts: {lib: vue-cli-service build --target lib --name selector --dest lib packages/index.js
}⑫执行编译命令 yarn lib或num run lib 执行结果如下图 然后在项目根目录会生成如下图所示文件夹 ⑬在终端执行 npm init 初始化包配置文件package.json 可忽略这一步 package.json部分截图如下 name: 包名该名字是唯一的。可在 npm 官网搜索名字不可重复。 version: 版本号每次发布至 npm 需要修改版本号不能和历史版本号相同。 main: 入口文件需指向最终编译后的包文件。 author作者 private是否私有需要修改为 false 才能发布到 npm ⑭在项目根目录创建 .npmignore 文件设置忽略发布的文件类似 .gitignore 文件 只有编译后的 lib 目录、package.json、README.md是需要被发布的# 忽略目录.DS_Storenode_modulespackages/public/src/# 忽略指定文件.eslintrc.cjs.gitignore.npmignore.npmrcbabel.config.jsvue.config.jsyarn.lock*.map⑮编写README.md文件使用markdown格式 参考文档 http://markdown.p2hp.com/index.html
# vue-amazing-selector## An Amazing Select Component For Vue2## Install Usesh
npm install vue-amazing-selector
#or
yarn add vue-amazing-selectorImport and register component
Global
import Vue from vue
import VueAmazingSelector from vue-amazing-selector
Vue.use(VueAmazingSelector)Local
templateVueAmazingSelector:optionsoptionslabellabelvaluevalueplaceholder请选择:disabledfalse:width160:height36:num6v-modelselectedValuechangeonChange /
/template
script
export default {name: App,data () {return {options: [{label: 北京市,value: 1},{label: 上海市上海市上海市上海市,value: 2,disabled: true},{label: 郑州市,value: 3},{label: 纽约市纽约市纽约市纽约市,value: 4},{label: 旧金山,value: 5},{label: 悉尼市,value: 6},{label: 伦敦市,value: 7},{label: 巴黎市,value: 8}],selectedValue: 1}},watch: {selectedValue (to) {console.log(selectedValue:, to)}},mounted () {setTimeout(() { // 模拟接口调用this.selectedValue 3}, 1000)},methods: {onChange (value, label, index) {console.log(item:, value, label, index)}}
}
/script## Props| 属性 | 说明 | 类型 | 默认值 |
| :--- | :--- | :--- | :--- |
options | 选项数据 | Array | []
label | 选择器字典项的文本字段名 | String | label
value | 选择器字典项的值字段名 | String | value
placeholder | 选择框默认文字 | String | 请选择
disabled | 是否禁用下拉 | Boolean | false
allowClear | 是否支持清除 | Boolean | false
width | 选择框宽度 | Number | 200
height | 选择框高度 | Number | 36
num | 下拉面板最多能展示的下拉项数超过后滚动显示 | Number | 6
selectedValue | v-model当前选中的option条目 | /Number/String | null## Events事件名 | 说明 | 返回值
:--- | :--- | :---
change | 选择某项下拉后的回调函数 | value, label, indexvalue值label文本值index索引值⑯登录npm 如果没有npm账号可以去npm官网 npm 注册一个账号
注册成功后在本地查看npm镜像
npm config get registry输出https://registry.npmjs.org 即可
如果不是则需要设置为npm镜像
npm config set registry https://registry.npmjs.org然后在终端执行
npm login依次输入用户名密码邮箱
输出Logged in as…即可
npm whoami // 查看当前用户是否已登录⑰发布组件到npm 在终端执行npm publish
发布成功后即可在npm官网搜索到该组件如下图并可以通过 npm install my-popup-selector或yarn add my-popup-selector进行安装 ⑱在要使用的项目中安装并注册插件 yarn add my-popup-selector
// 在 main.js 文件中引入并注册
import Vue from vue
import VueAmazingSelector from my-popup-selector
Vue.use(VueAmazingSelector)在要使用组件的页面直接使用即可 templateVueAmazingSelector:optionsoptionslabellabelvaluevalueplaceholder请选择:disabledfalse:width160:height36:num6v-modelselectedValuechangeonChange /
/template
script
export default {name: App,data () {return {options: [{label: 北京市,value: 1},{label: 上海市上海市上海市上海市,value: 2,disabled: true},{label: 郑州市,value: 3},{label: 纽约市纽约市纽约市纽约市,value: 4},{label: 旧金山,value: 5},{label: 悉尼市,value: 6},{label: 伦敦市,value: 7},{label: 巴黎市,value: 8}],selectedValue: 1}},watch: {selectedValue (to) {console.log(selectedValue:, to)}},mounted () {setTimeout(() { // 模拟接口调用this.selectedValue 3}, 1000)},methods: {onChange (value, label, index) {console.log(item:, value, label, index)}}
}
/script如果遇到less-loader版本过高问题 yarn add less-loader安装版本过高报错如图 解决yarn add less-loader6.0.0