vue插件的创建,开发,发布(可自由拖拽,拉伸的面板)

现在以插件名为 vue-drag-infinite为例,具体内容可通过以下方式进行下载
github查看源代码

npm install --save vue-drag-infinite

第一步初始化一个项目

封装vue的插件用webpack-simple很合适,使用命令:vue init webpack-simple vue-gitment 进行项目初始化,项目结构如下图所示:


初始化项目结构

1 首先打开清除掉无用的文件 具体清除内容为:

1.src下的所有文件
2.根目录下的 index.html 文件

2 修改根目录下的 package.json 里的内容

{
  "name": "vue-drag-infinite",// 插件名称 再初始化项目的时候 可以设置 也可以在这里进行修改
  "description": "A Vue.js project",//插件描述
  "version": "1.1.2",//版本号 每次向npm上 publish的时候要修改一下 自增的形式
  "author": "zhaosq <615683167@qq.com>",
  "license": "MIT",//许可证
  "private": false,//默认是true 私人的 需要改为false 
  "main":"dist/vue-drag-infinite.js",//这个超级重要 决定了你 import xxx from “vue-drag-infinite” 它默认就会去找 dist下的vue-drag-infinite 文件
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
  },
  "dependencies": {
    
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "devDependencies": {
    "babel-core": "^6.26.0", // 依赖包名称  以及对应的版本号
    ........ 此处依赖吧不做解释
  }
}

3.修改根目录下方的 webpack.config.js文件内容

var path = require('path')
var webpack = require('webpack')// commonjs 的形式引入webpack
module.exports = {
  // entry: './src/main.js',
  entry: './src/lib/index.js',//文件入口
  output: {//文件出口配置
    path: path.join(__dirname, './dist'),// 出口路径
    publicPath: '/dist/',//build打包路径
    filename: 'vue-drag-infinite.js',//打包后文件名称  设置为与插件名称一致
    libraryTarget:'umd',//libraryTarget会生成不同umd的代码,可以只是commonjs标准的,也可以是指amd标准的,也可以只是通过script标签引入的。
    library:'VueDragInfinite',//library指定的就是你使用require时的模块名,这里便是require("VueDragInfinite")
    umdNamedDefine:true//会对 UMD 的构建过程中的 AMD 模块进行命名。否则就使用匿名的 define。
  },
  module: {.....},//对应 vue文件 js文件 css文件 url文件 sass文件 style行内样式 进行解析
  devtool: '#eval-source-map',//相关选项有几种 不再过多解释,现在要做的是在打包后不再生成.map结尾的文件  将值设为 false
}

4.进行插件内容的编写 根据vue官网要求 需要使用 install

先在 src文件下创建 lib文件夹 在lib文件夹下创建一个 index.js 和一个 vue-drag-infinite.vue文件
index.js文件内容如下

import vueDragInfinite from './vue-drag-infinite.vue'
const dragInfinite = {
    install(Vue, options) {
        Vue.component(vueDragInfinite.name, vueDragInfinite) // vuePayKeyboard.name 组件的name属性
        // 类似通过 this.$xxx 方式调用插件的 其实只是挂载到原型上而已
        // Vue.prototype.$xxx  // 最终可以在任何地方通过 this.$xxx 调用
        // 虽然没有明确规定用$开头  但是大家都默认遵守这个规定
    }
}
if (typeof window !== 'undefined' && window.Vue) {
    window.Vue.use(dragInfinite);
}
export default dragInfinite;

vue-drag-infinite.vue文件内容如下

<template>
    <div class="contain" ref="dragContain">
        <div class="control" v-drag="contain">
            <div style="line-height:30px;background:#409EFF;cursor:move;color:#fff;text-indent:15px;">
                控制面板
            </div>
            <div style="padding:7px;" @mousedown="mouseDown($event,false)">
                <el-form ref="form" size="mini" label-width="70px">
                  <el-form-item label="模板名称">
                    <el-input v-model="name"></el-input>
                  </el-form-item>
                  <el-row  v-if="json.length">
                      <el-form-item>
                        <el-button type="primary" @click="onSave">保存</el-button>
                      </el-form-item>
                      <el-form-item label="宽度">
                        <el-input v-model.lazy="json[divindex].style.width"></el-input>
                      </el-form-item>
                      <el-form-item label="高度">
                        <el-input v-model.lazy="json[divindex].style.height"></el-input>
                      </el-form-item>
                      <el-form-item label="字体大小">
                        <el-select v-model.lazy="json[divindex].style.fontSize" placeholder="请选择字体大小">
                          <el-option label="12px" value="12px"></el-option>
                          <el-option label="14px" value="14px"></el-option>
                          <el-option label="16px" value="16px"></el-option>
                          <el-option label="18px" value="18px"></el-option>
                        </el-select>
                      </el-form-item>
                      <el-row>
                          <el-col :span="12">
                            <el-form-item label="背景颜色">
                            <el-color-picker v-model.lazy="json[divindex].style.backgroundColor" show-alpha></el-color-picker>
                            </el-form-item>
                          </el-col>
                          <el-col :span="12">
                            <el-form-item label="文字颜色">
                            <el-color-picker v-model.lazy="json[divindex].style.color"></el-color-picker>
                            </el-form-item>
                          </el-col>
                      </el-row>
                        
                      <el-form-item label="文字内容">
                        <el-input type="textarea" v-model="json[divindex].text"></el-input>
                      </el-form-item>
                  </el-row>
                    <el-row>
                      <el-button type="primary" size="mini" @click="addDive()">新增div</el-button>
                    </el-row>
                </el-form>
            </div>
        </div>
        
        <div v-drag="contain" class="drag" :class="{active:index == divindex}" v-if="json.length" v-for="(item,index) in json" @click="moveDiv(index,$event)" :style="item.style">
            {{item.text}}
            <i class="el-icon-menu sacle" v-if="index == divindex" @click="sacle($event)" @mousedown="mouseDown($event,true)"  unselectable="on"></i>
            <el-button type="danger" class="del"  @click="del(index,$event)" v-if="index == divindex" icon="el-icon-delete" circle></el-button>
        </div>
        <div v-if="!json.length">暂时没有内容哦!!期待您的编辑</div>
    </div>
</template>
<script >
export default {
    name:'vue-drag-infinite', // 此处name名称  在index.js 文件中有引用  所以最好跟插件名称一致,避免chux
    props: {
        json: {
            type: Array,
            default: []
        },
        name: {
            type: String,
            default: '小清新'
        },
    },
    data(){
        return {
            //外层容器的宽高 数值不带px单位
            contain:{
                xx:500,
                yy:500
            },
            //存放拉伸放大时的  div的原始宽高 带px单位
            movejson:{
                moveWidth:'',
                moveHeight:''
            },
            divindex:0,//当前选中div的序号  默认为0
        }
    },
    mounted(){  
        this.contain.xx = this.$refs.dragContain.offsetWidth;
        this.contain.yy = this.$refs.dragContain.offsetHeight;
    },
    methods:{
        // 字符串转json对象
        toJson(str){
          let _str =eval('(' + str + ')');
          return _str;
        },
        //外层div点击选择事件 绑定右上角设置面板
        moveDiv(index,e){
            let jsonNew = this.toJson('{"'+e.target.style.cssText.replace(/\; +/g, "\",\"").replace(/\: +/g, "\":\"").replace(/\;+/g, "").replace(/-\w/g, function ($) {return $.slice(1).toUpperCase();})+'"}');
            //当前选中div的序号
            this.divindex = index;
            // 设置div框的 各种属性
            for (let em in jsonNew) {
                this.json[index].style[em]= jsonNew[em]; 
            }
            this.json[index].text= e.target.innerText;
        },
        //添加一个div块 默认的
        addDive(){
            let newJson = {
                style:{
                    width:"80px",
                    height:"50px",
                    fontSize:"14px",
                    color:"#ffffff",
                    backgroundColor:"#333333"
                },
                text:'新的div'
            };
            this.json.push(newJson);
        },
        //删除当前div
        del(i,e){
            this.json.splice(i, 1);
            if(i == this.json.length){
                this.divindex = 0;
            }
            e.stopPropagation();
        },
        onSave(){
            let data = this.json;
            this.$emit('save',data)
        },
        //div上拉伸的阻止冒泡事件
        sacle(e){
            e.stopPropagation();
        },
        //div上拉伸的 放大 缩小div宽高
        mouseDown(e,type){
            if(type){
                let that = this;
                let oldX = e.pageX,oldY = e.pageY;
                that.movejson.moveWidth = that.json[that.divindex].style.width;
                that.movejson.moveHeight = that.json[that.divindex].style.height;
                document.onmousemove = function (e){
                    let newX = e.pageX - oldX;
                    let newY = e.pageY - oldY;
                    that.json[that.divindex].style.width = ((newX+ parseInt(that.movejson.moveWidth))>=80?(newX+ parseInt(that.movejson.moveWidth)):'80')+'px';
                    that.json[that.divindex].style.height = ((newY+ parseInt(that.movejson.moveHeight))>=50?(newY+ parseInt(that.movejson.moveHeight)):'50')+'px';
                }
                document.onmouseup = function(){
                    document.onmousemove = document.onmouseup = null;
                }
            }
            e.stopPropagation();
        }
    },
    computed: {
    },
    directives:{
        drag:{
            bind: function (el, binding, vnode) {
              el.onmousedown = function(e){
                var disx = e.clientX - el.offsetLeft;
                var disy = e.clientY - el.offsetTop;
                document.onmousemove = function (e){
                    let left = e.clientX - disx;
                    let top = e.clientY - disy;
                    if(left<0){
                        left = 0;
                    }
                    if(top<0){
                        top = 0;
                    }
                    if(left>binding.value.xx-el.offsetWidth){
                        left = binding.value.xx-el.offsetWidth;
                    }
                    if(top>binding.value.yy-el.offsetHeight){
                        top = binding.value.yy-el.offsetHeight;
                    }
                    el.style.left = left+'px';
                    el.style.top = top+'px';
                }
                document.onmouseup = function(){
                    document.onmousemove = document.onmouseup = null;
                }
            }
          },
        }
    }

}

</script>
<style lang='scss' scoped>
    ul,li{margin:0px;list-style:none;padding:0px;}
    .contain{height: 700px;background:#ddd; position: relative;user-select:none;}
    .el-form-item--mini.el-form-item{
        margin-bottom:7px;
    }
    .drag{
            width: 100px;
            height: 100px;
            position: absolute;
            top: 0;
            left: 0;
            cursor:move;
            background-color: red;
            border:1px solid #FFF;
            line-height:1.7;
            box-sizing:border-box;
            color:#fff;
            overflow: hidden;
            padding:5px;
            .sacle{
                position:absolute;
                right:0px;
                bottom:0px;
                background-color:#909399;
                cursor: se-resize;
                font-size:15px;
            }
            .del{
                position:absolute;
                top:0px;
                right:0px;
                padding:5px;
                box-shadow:0px 0px 10px rgba(255, 255, 255,0.5);
            }
    }
    .drag.active{
        border-radius:5px;
        border:1px solid #85ce61;
        box-shadow:0px 0px 20px rgba(0,0,0,0.5);
        
    }
    .control{
        width:250px;
        border-radius:5px;
        overflow:hidden;
        background-color:#B3C0D1;
        position:absolute;
        z-index:999;
        right:20px;
        top:15px;
    }

</style>

5.插件打包 build

npm run build 在dist文件夹中会出现一个vue-drag-infinite.js 文件
由于在webpack.config.js 中设置了 devtool:false,所以不会出现.map文件

下一步 npm插件的发布

首先在npm官网上进行账号的注册,各位自行注册
下载git工具,在git官网上进行下载 主要有俩个命令

npm login //登陆
npm publish //上传

publish后的文件找不到dist文件夹
原因是我们的忽略文件默认忽略了 dist 文件
修改根目录下的 .gitignore 去掉忽略dist

git登陆上传详情

关于出现各种npm publish 失败的情况 可以观看本人另一篇文章
点击这里

最后说一下 关于插件的使用描述 md文件的编写

详细语法可以自行百度


代码编写区域
# h1标签  ## h2标签 ###### h6 标签

以上内容 个人手打与总结,有错误的地方还望各位大神指出

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容