专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序员的那些事  ·  清华大学:DeepSeek + ... ·  3 天前  
程序员小灰  ·  清华大学《DeepSeek学习手册》(全5册) ·  3 天前  
OSC开源社区  ·  宇树王兴兴早年创业分享引围观 ·  4 天前  
OSC开源社区  ·  升级到Svelte ... ·  5 天前  
51好读  ›  专栏  ›  SegmentFault思否

手把手教你撸个vue2.0弹窗组件

SegmentFault思否  · 公众号  · 程序员  · 2017-11-21 08:00

正文

在开始之前需要了解一下开发vue插件的前置知识,推荐先看一下vue官网的插件介绍(https://cn.vuejs.org/v2/guide/plugins.html)

预览地址:http://haogewudi.me/kiko/index.html

源码地址:https://github.com/rascalHao/kiko

搭建项目

1.vue-cli将你的vue项目初始化建好 vue init webpack my-project

2.平常我们引入插件的流程是:

  1.    npm i -S

  2.    import Vue from 'vue'

  3.    import xxx from 'xxx'

  4.    Vue.use(xxx)

所以可以在node_modules下面新建一个你的开发目录,我这里命名为kiko,所以现在大概引入我们的开发插件的步骤为(项目最终构建完会采取发布npm包的形式)

  1.    import Vue from 'vue'

  2.    import Kiko from '../node_modules/kiko/index.js'

  3.    Vue.use(Kiko)

3.在你的项目目录下通过npm init指令来初始化一个package.json文件,默认指定你的入口文件index.js,并在你的项目根目录下新建一个index.js入口文件

4.这里会构建4中类型的弹窗组件(message、toolTip、confirm、loading),基本的结构如图所示:


入口文件(可以先略过)

Vue.js 的插件应当有一个公开方法 install 。这个方法的第一个参数是 Vue 构造器 , 第二个参数是一个可选的选项对象;通过全局方法 Vue.use() 使用插件;可以再次看下vue官网的插件介绍

  1.    import KikoMessage from './packages/message/index.js'

  2.    import KikoToolTip from './packages/tips/index.js'

  3.    import KikoConfirm from './packages/confirm/index.js'

  4.    import KikoLoading from './packages/loading/index.js'

  5.    const install = function(Vue) {

  6.      Vue.component(KikoMessage.name, KikoMessage)

  7.      Vue.component(KikoToolTip.name, KikoToolTip)

  8.      Vue.component(KikoConfirm.name, KikoConfirm)

  9.       Vue.component(KikoLoading.name, KikoLoading)

  10.      Vue.prototype.$kiko_tooltip = KikoToolTip.installToolTip

  11.      Vue.prototype.$kiko_message = KikoMessage.installMessage

  12.    }

  13.    export default install

message


在项目的根目录创建message组件,通过

  1. Vue.prototype.$kiko_message = function (methodOptions) {

  2.    // 逻辑...

  3.  }

来添加实例方法全局以调用this.$kiko_message()的方式来调用message

message组件结构

main.vue
  1.    

  2.       name="fade">

  3.        

    class="kiko-message" v-if="isShow">
  4.          {{message}}

  5.        

  • false

  •            }, this.time);

  •          }

  •        }

  •      }

  •    

  • index.js
    1.    import Vue from 'vue'

    2.    import Message from './src/main.vue'

    3.    Message.installMessage = function(options) {

    4.      if (options === undefined || options === null) {

    5.        options = {

    6.          message: ''

    7.        }

    8.      } else if (typeof options === 'string' || typeof options === 'number') {

    9.        options = {

    10.          message: options

    11.        }

    12.      }

    13.       var message = Vue.extend(Message)

    14.      var component = new message({

    15.        data: options

    16.      }).$mount()

    17.      document.querySelector('body').appendChild(component.$el)

    18.    }

    19.     export default Message

    到这里的时候可以看下前面的入口文件介绍,你需要通过Vue.component注册为组件,并把Message.installMessage方法绑定到Vue.prototype.$kiko_message上。

    toolTip

    没有选择通过固化在页面中的方式来引入toolTip,因为考虑到可能在页面中的任何地方引入toolTip,如果固化了,将会大大限制toolTip的使用场景。所以采用了一个绑定到Vue.prototype的this.$kiko_tooltip全局方法来触发,这样就可以自定义触发方式,只需要通过传入$event就可以自动地定位任何有需要的元素了。

    toolTip组件结构

    同message组件结构

    main.vue
    1.  

    2.    

      v-if="isShow" id="kiko_tool_tip" class="kiko-tool-tip" :class="{'left': direction === 'left', 'right': direction === 'right', 'top': direction === 'top', 'bottom': direction === 'bottom'}" :style="{'background-color': background, 'color': color, 'top': top, 'left': left}">
    3.      {{content}}

    4.      

      class="arrow" :style ="arrowStyleObject">

    5.    

    6.  

    7.   ,

    8.          direction: 'right',

    9.          background: 'red',

    10.          color: '#fff',

    11.          arrowStyleObject: ''

    12.        }

    13.      },

    14.      beforeMount () {

    15.        let node = document.querySelector('#kiko_tool_tip')

    16.        if (node && node.parentNode) {

    17.          node.parentNode.removeChild(node)

    18.        }

    19.      },

    20.      computed: {

    21.        top () {

    22.          switch (this.direction) {

    23.            case 'top':

    24.              return (this.rect.top - 12) + 'px'

    25.            case 'bottom':

    26.              return (this.rect.top + 12) + 'px'

    27.            case 'left':

    28.              return (this.rect.top + this.rect.height / 2) + 'px'

    29.            case 'right':

    30.              return (this.rect.top + this.rect.height / 2) + 'px'

    31.          }

    32.        },

    33.        left () {

    34.          switch (this.direction) {

    35.            case 'top':

    36.              return (this.rect.left + this.rect.width / 2) + 'px'

    37.            case 'bottom':

    38.              return (this.rect.left + this.rect.width / 2) + 'px'

    39.            case 'left':

    40.              return (this.rect.left - 12) + 'px'

    41.            case 'right':

    42.              return (this.rect.left + this.rect.width + 12) + 'px'

    43.          }

    44.        }

    45.      },

    46.      mounted () {

    47.        this.initColor()

    48.        this.hidden()

    49.      },

    50.      methods: {

    51.        initColor () {

    52.          switch (this.direction.toLowerCase()) {

    53.            case 'left':

    54.              this.arrowStyleObject = {

    55.                borderLeftColor: this.background

    56.              }

    57.              break;

    58.            case 'right':

    59.              this.arrowStyleObject = {

    60.                borderRightColor: this.background

    61.              }

    62.              break;

    63.            case 'top':

    64.              this.arrowStyleObject = {

    65.                borderTopColor: this.background

    66.              }

    67.              break;

    68.            case 'bottom':

    69.              this.arrowStyleObject = {

    70.                borderBottomColor: this.background

    71.              }

    72.              break;

    73.          }

    74.        },

    75.        hidden () {

    76.          let that = this

    77.          window.setTimeout(function(){

    78.            that.isShow = false

    79.          }, this.time)

    80.        }

    81.      }

    82.    }

    83.  

    84.  

    index.js
    1.   import Vue from 'vue'

    2.  import ToolTip from './src/main.vue'

    3.  ToolTip.installToolTip = function(event, opt) {

    4.    var options = opt

    5.    var rect = {};

    6.    ['top', 'left'].forEach(function(property) {

    7.       var scroll = property === 'top' ? 'scrollTop' : 'scrollLeft'

    8.      rect[property] = event.target.getBoundingClientRect()[property] +

    9.        document.body[scroll] +

    10.        document.documentElement[scroll]

    11.    });

    12.    ['height', 'width'].forEach(function(property) {

    13.      rect[property] = event.target.getBoundingClientRect()[property]

    14.    });

    15.    options.rect = rect

    16.    var toolTip = Vue.extend(ToolTip)

    17.    var component = new toolTip({

    18.      data: options

    19.    }).$mount()

    20.    event.target.appendChild(component.$el)

    21.  }

    22.   export default ToolTip

    通过Element.getBoundingClientRect()方法获取元素的大小及其相对于视口的位置,之后对提示信息进行fixed定位。

    confirm

    confirm在保留页面的情况下会弹出一个对话框,适合一些场景更大的情况。可以用来进行一些复杂带校验的弹窗信息展示,也可以只用于简单信息的展示。可以通过title属性来显示任意标题,通过width属性来修改显示区域的宽度。

    confirm组件结构

    同message组件

    main.vue
    1.  

    2.     name="bounce">

    3.      

      class="kiko-confirm" v-if="visible">
    4.        

      class="bg">

    5.        

      class="kiko-container" :style="{width: width}">
    6.          

      class="header">
    7.            {{title}}

    8.             @click="close" class="icon-remove icon-large kiko-close-btn" v-if="closeVisible">

    9.          

    10.          

      class="content">
    11.            

    12.          

    13.           name="footer">

    14.            

    15.          

    16.        

    17.      

    18.    

    19.  

    20.  







    请到「今天看啥」查看全文