vue-menu菜单 从开发到npm包发布
最近在开发vue项目,其中一些组件采用自研的方式开发,在这里对于一些通用性较强的组件进行一些总结,本文记录一下vue-menu菜单组件的开发过程和npm包发布过程。一、组件的开发1、需求分析组件需要的功能:(1)点击或者鼠标hover某一元素后弹出下拉菜单;(2)下拉菜单项具备点击功能;(3)下拉项可以置灰,点击无效;(4)可以为下拉菜单添加自定义的类;2、创建项目...
最近在开发vue项目,其中一些组件采用自研的方式开发,在这里对于一些通用性较强的组件进行一些总结,本文记录一下vue-menu菜单组件的开发过程和npm包发布过程。
一、组件的开发
1、需求分析
组件需要的功能:
(1)点击或者鼠标hover某一元素后弹出下拉菜单;
(2)下拉菜单项具备点击功能;
(3)下拉项可以置灰,点击无效;
(4)可以为下拉菜单添加自定义的类;
2、创建项目:
vue init webpack vue-menu
设置项目配置,完成后再src文件夹下创建vmenu文件夹,包含一个index.js文件和一包含main.vue的src文件夹。
构建项目目录如图:
其中main.vue为下拉菜单的源代码文件,用来组织菜单结构,index.js作为组件的入口文件。
2.1 main.vue文件
main.vue文件中以ul标签和li标签的形式展示用户传入的list数据,并绑定li的点击事件,具体代码实现如下
main.vue模板:
<template>
<div id='v-menu-wrap-div' class='v-menu-wrap' :style='{left:rect.left +"px",top:rect.top + rect.height + "px"}' >
<ul ref='v-menu-ul' class='vmenu-operate-ul' :class='ulClass'>
<li v-for='liItem in list' @click='clickLiBtn(liItem)' :class='[liItem.disabled ===true ? "disabled":"",liItem.class]'>
<span v-if='liItem.icon' class='v-menu-span-icon operate-icon' :class='liItem.icon'></span>
<span>{{liItem.text}}</span>
</li>
</ul>
</div>
</template>
main.vue的script标签:
<script>
export default{
name:'vMenu',
methods:{
clickLiBtn(li){
if(li.disabled){ //如果有disabled属性,则返回
return;
}else if(li.clickFun){
li.clickFun(li);
}
}
},
data: function(){
return {
}
},
}
</script>
修改样式:
<style >
div.v-menu-wrap{
position:absolute;
z-index:9999;
}
ul.vmenu-operate-ul{
list-style: none;
color:black;
float: left;
min-width: 160px;
padding: 5px 0;
margin: 2px 0 0;
font-size: 14px;
text-align: left;
background-color: #fff;
box-shadow: 0 6px 12px rgba(0,0,0,.175);
border: 1px solid rgba(0,0,0,.15);
}
ul.vmenu-operate-ul li{
line-height:20px;
display: list-item;
padding:3px 20px;
cursor:pointer;
}
ul.vmenu-operate-ul li:hover{
color: #fff;
background-color: #39ace5;
}
ul.vmenu-operate-ul li.disabled,ul.vmenu-operate-ul li.disabled:hover{
background-color:white;
cursor:default;
}
ul.vmenu-operate-ul li.disabled span,ul.vmenu-operate-ul li.disabled:hover span{
color: rgb(167, 167, 167);
}
</style>
2.2 index.js入口文件
入口文件需包含一个导出对象,对象有一个install方法,在使用Vue.use('xxx')时,会调用该install方法,方法的第一个参数为Vue实例:
import vMenu from './src/main';
vMenu.install = function(Vue){
};
export default vMenu;
补充实例方法:
/**
* @file :vue的menu菜单实现,通过实例$menu(options)调用
* @Author: panjianfeng
* @e-mail: jianfeng418@sina.com
* @createDate:2018-11-29
*/
import vMenu from './main/main.vue';
const install = function(Vue){
Vue.prototype.$menu = function(event,options){
var rect = {};
['top','left'].forEach(function(property){
var scroll = property === 'top' ? 'scrollTop' :'scrollLeft' ;
rect[property] = event.currentTarget.getBoundingClientRect()[property] + document.body[scroll] + document.documentElement[scroll];
});
rect['left'] = rect['left'] + 160 > document.body.offsetWidth ? document.body.offsetWidth-160 : rect['left'];
['height','width'].forEach(function(property){
rect[property] = event.currentTarget.getBoundingClientRect()[property];
});
if(options){
options.rect = rect;
options.ulClass = options.ulClass ? options.ulClass :'';
}else{
let node = document.querySelector('#v-menu-wrap-div');
if(node && node.parentNode){
node.parentNode.removeChild(node);
};
return ;
}
var vmenu = Vue.extend(vMenu);
var componentMenu = new vmenu({
data:options
}).$mount();
let node = document.querySelector('#v-menu-wrap-div');
if(node){
node.parentNode.removeChild(node);
}
Vue.nextTick(function(){
document.body.appendChild(componentMenu.$el);
});
const removeNode = function(){
let node = document.querySelector('#v-menu-wrap-div');
if(node){
node.parentNode.removeChild(node);
document.onclick = null;
document.removeEventListener('click',removeNode,true);
}
}
document.addEventListener('click',removeNode,true);
};
};
export default install;
2.3 测试
<template>
<div class="hello">
<h3>{{ msg }}</h3>
<span @click='showMenu'>点我下拉菜单</span>
</div>
</template>
<script>
......
methods:{
showMenu(event){
this.$menu(event,{
list:[{
icon:'',
text:'vue',
clickFun:this.showAlert,
},{
icon:'',
text:'javascript',
clickFun:this.showAlert,
},{
icon:'',
text:'html',
disabled:true,
clickFun:this.showAlert,
},{
icon:'',
text:'css',
disabled:false,
clickFun:this.showAlert,
}],
ulClass:'menuclass'
})
},
showAlert(item){
alert(item.text)
}
</script>
效果如下:
至此,组件开发工作完成。
github完整代码:
GitHub - jianfeng418/vue-menu: menu width vue
二、npm包发布
1、 通过webpack-simple新建项目,
vue init webpack-simple vue-menu
通过webpack-simple创建一个简易的项目,用于对源代码进行压缩,方便上传,使用。
1.1 将vue-menu的源代码拷贝到src文件夹下:
1.2 修改webpack.config.js:
注意:该例子中将文件输出到dist文件夹下,而项目的.gitignore文件默认把dist/文件夹忽略,因此,修改.gitignore文件,删除/dist/行:
1.3 npm run build
运行该命令,构建生产项目后,查看dist文件夹,产生两个文件
1.4 修改package.json文件
name:修改为唯一的名称,和现有npm库不能冲突。该名称即为npm包的名称,用户通过该名称下载组件使用。
private:改为false;
main:用户引用组件时,系统通过该字段去寻找文件,即用户实际引用的文件,这里改成构建后的压缩文件;
1.5 登录npm账户
npm login
如果没有npm账号,先去npm官网注册自己的用户账号;
输入用户名、密码、邮箱后,显示登录成功的信息;
可通过npm whoami 命令查看当前npm用户:
1.6 发布npm
通过npm publish命令发布自己的包;注意包的名称必须是现有npm库不存在的名称;否则会发布失败;
登录npm官网,登录自己账号可以看到已经发布的npm包;
1.7 验证
下载刚刚上传的包:
npm install vue-menu-jf -S
在new Vue前引入vMenu,在项目中引用:
import vMenu from 'vue-menu-jf'
Vue.use(vMenu);
验证成功,完成。
1.8 npm包升级
在升级已经发布的npm包时,需要更改package.json中的version字段,同样使用npm publish 命令发布。
更多推荐
所有评论(0)