Vue组件化|通用组件开发——Notification通知组件封装

2020-03-11 21:21:05

参考地址 Vue组件化|通用组件开发——Notification通知组件

1. 基础组件编写


1.1 组件目录结构




1.2 组件文件代码


<template>

  <transition name="fade">

    <div :style="style">

      <span>{{content}}</span>

      <a @click="handleClose">{{btn}}</a>

    </div>

  </transition>

</template>

 

<script>

export default {

  name: 'Notification',

  props: {

    content: {

      type: String,

      required: true

    },

    btn: {

      type: String,

      default: '关闭'

    }

  },

  computed: {

    style () {

      return {}

    }

  },

  methods: {

    handleClose (e) {

      e.preventDefault()

      this.$emit('close')

    }

  }

}

</script>

 

<style scoped>

.notification

  display flex

  background-color #303030

  color rgba(255, 255, 255, 1)

  align-items center

  padding 20px

  position fixed

  min-width 280px

  box-shadow 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.8)

  flex-wrap wrap

  transition all .3s

  .content

    padding 0

  .btn

    color #ff4081

    padding-left 24px

    margin-left auto

    cursor pointer

</style>

 

1.3 组件使用的过渡效果样式代码


html, body{

  margin: 0

  padding: 0

  width: 100%

  height: 100%

}

 

body{

  background-image: url(../images/beijing.jpg)

  background-size: cover

  background-position: center

  font: 14px/1.5 tahoma,arial,'Hiragino Sans GB','\5b8b\4f53',sans-serif

  color: #4d4d4d

  -webkit-font-smoothing: antialiased // 这个属性可以使页面上的字体抗锯齿,使用后字体看起来会更清晰舒服

  font-weight: 300

}

 

.fade-enter-active, .fade-leave-active{

  transition: opacity .5s  

}

.fade-enter, .fade-leave-to{

  opacity: 0  

}

1.4 如果我们直接使用这个编写好的组件,只能是我们在编写一个Vue组件的时候引用这个Notification的组件把它写在模版里面,把它去显示出来,我们这里作为一个全局通用型组件,而且我们可以把它发布到第三方去使用的组件,所以我们这里会为其提供一个类似于Vue插件的使用方法。




友情提醒:我们在定义组件的时候最好都给组件定义一个name,因为我们去编写一个组件库,我们会有非常多的组件要注册到全局的Vue的组件里面,这个时候如果没有一个name,那么每个组件注册的时候都需要用字符串去写name,这个维护性是非常不好的,如果你在组件内部就把组件的name定义好,那就可以很方便的把组件一个个定义过去就OK了。


1.5 入口文件引入组件,然后将其定义为插件即可再全局使用该组件了




1.6 在app组件中使用我们自定义的通知组件,直接使用即可无需再次注册




1.7 打开浏览器查看显示效果




1.8 总结


现在看我们这个组件的静态展示效果已经出现了,基本也就是这个样子,我们使用组件的时候需要在模版里面去定义,而且它还没有变成全局性的那种提示要从右下角弹出来,我们如果要在模版里进行这种效果控制还需要给组件添加属性visible用来控制组件的显示隐藏,然后在我们自己的逻辑中判断什么时候该显示什么时候该消失,整个逻辑就会变得很复杂,那我们用起来非常的困难,因为这种是临时性的组件,等到某个特殊的情况才需要我们去Notification一下,那么如果我们写在模版里,则一开始就需要定义好这个组件而且需要控制这个组件是不显示的,这种用法明显感觉是很奇怪的。所以,后面我们就要去改进它,让我们自定义的这个组件可以通过Vue的一些功能去实现我们可以通过API的方式去调用它。用起来就会变得非常方便了~


2. 通过API方式调用组件


2.1 扩展Notification组件,因为只有上面定义的两个属性是不够使用的,所以我们使用Vue.extends去扩展这个组件,为什么我们不在原来的组件是直接进行修改呢?因为那些属性添加上之后,如果我们在app.vue组件中在模版中使用这个组件的时候就会变得不好用,因此我们选择去扩展组件,而不是去修改原来的组件。这样既可以复用原来组件的代码,然后又可以达到我们扩展功能的目的。那么我们如何去扩展我们原来的组件呢?需要新创建一个文件,专门用来做API调用时使用的。




代码:


import Notification from './notification.vue'

 

export default {

  extends: Notification,

  data () {

    return {

      verticalOffset: 0

    }

  },

  computed: {

    style () {

      return {

        position: 'fixed',

        right: '20px',

        bottom: `${this.verticalOffset}px`

      }

    }

  }

}

2.2 编写API调用逻辑处理文件




代码:


import Vue from 'vue'

import Component from './func-notification'

 

/**

 * 思考:我们为什么要这么去做呢?因为我们这里是一个方法,我们要通过JS的方法调用去创建一个Vue的组件,这个组件我们怎么去创建最方便呢?

 * 我们肯定是通过去new的方式,我们可以直接通过new Vue去创建一个组件,那么我们同样可以通过Vue.extend返回的方法,我们去创建一个组件。

 */

const NotificationConstructor = Vue.extend(Component)

 

const instances = [] // 存储通知组件实例列表

let seed = 1 // 用来生成组件的id

 

const notify = (options) => {

  if (Vue.prototype.$isServer) return

 

  const instance = new NotificationConstructor({

    propsData: options

  })

  instance.id = `notification_${seed++}` // 生成唯一id,用来做删除时使用

  // 通过$mount()不传节点的时候,只是生成了一个$el的对象,但是这个时候还没有真正的插入到DOM节点里面去,此时标签节点已经生成好了

  instance.vm = instance.$mount()

  document.body.appendChild(instance.vm.$el)

 

  // 计算高度

  let verticalOffset = 0

  instances.forEach((item) => {

    verticalOffset += item.$el.offsetHeight + 16 // 每个组件高度间隔16px

  })

  verticalOffset += 16 // 最下面的组件底部距离最底部也有16px的间隙

  instance.verticalOffset = verticalOffset

 

  instances.push(instance)

  return instance.vm

}

 

export default notify

2.3 将编写的API调用方法挂载到Vue.prototype原型对象上,这样在Vue的实例中就可以直接使用this.$xxx方法了




代码:


import Notification from './notification.vue'

import notify from './function'

 

export default (Vue) => {

  Vue.component(Notification.name, Notification)

  Vue.prototype.$notify = notify

}

2.4 在app.vue组件中使用该API来生成通知




代码:


<template>

    <div>

        <notification content="测试通知组件模版使用" />

    </div>

</template>

 

<script>

export default {

    data () {

        return {}

    },

    mounted () {

        this.$notify({

            content: '测试通知组件API使用!!!',

            btn: 'close'

        })

    }

}

</script>

 

<style>

</style>

2.5 打开浏览器查看效果,通过API调用方式成功生成我们想要的组件效果!!!




3. 点击发送通知


3.1 接下来我们实现每次点击按钮发送通知




3.2 改造代码实现点击按钮发送通知




代码:


<template>

    <div>

        <!-- <notification content="测试通知组件模版使用" /> -->

        <button @click="notify">发送通知</button>

    </div>

</template>

 

<script>

export default {

    data () {

        return {}

    },

    mounted () {

        

    },

    methods: {

        notify () {

            this.$notify({

                content: '测试通知组件API使用!!!',

                btn: 'close'

            })

        }

    }

}

</script>

 

<style>

</style>

3.3 添加通知自动关闭功能




代码:


import Notification from './notification.vue'

 

export default {

  extends: Notification,

  data () {

    return {

      verticalOffset: 0,

      autoClose: 3000

    }

  },

  computed: {

    style () {

      return {

        position: 'fixed',

        right: '20px',

        bottom: `${this.verticalOffset}px`

      }

    }

  },

  mounted () {

    this.createTimer()

  },

  beforeDestory () {

    this.clearTimer()

  },

  methods: {

    createTimer () {

      if (this.autoClose) {

        this.timer = setTimeout(() => {

          /**

           * 思考:这里我们需要把我们的组件隐藏掉,如果直接将组件删除掉效果会比较差,所以我们也要通过transition去做,

           * 通过transition去做,我们就需要通过某个属性去控制我们组件的显示与否,所以我们在我们的组件上面去添加一个visible属性,

           * 该属性用来控制组件的显示与隐藏。在默认组件内部该属性值是true,也就是说默认是显示的。

           */

          this.visible = false

        }, this.autoClose)

      }

    },

    clearTimer () {

      if (this.timer) {

        clearTimeout(this.timer)

      }

    }

  }

}

调用API修改




代码:


import Vue from 'vue'

import Component from './func-notification'

 

/**

 * 思考:我们为什么要这么去做呢?因为我们这里是一个方法,我们要通过JS的方法调用去创建一个Vue的组件,这个组件我们怎么去创建最方便呢?

 * 我们肯定是通过去new的方式,我们可以直接通过new Vue去创建一个组件,那么我们同样可以通过Vue.extend返回的方法,我们去创建一个组件。

 */

const NotificationConstructor = Vue.extend(Component)

 

const instances = [] // 存储通知组件实例列表

let seed = 1 // 用来生成组件的id

 

const notify = (options) => {

  if (Vue.prototype.$isServer) return

 

  /**

   * 我们希望我们的func-notification组件中的autoClose属性是通过options传入的,但是又不希望它是通过props传入而是作为data使用的,

   * 那么我们如何处理呢?我们可以拿到options形式传入的autoClose参数,然后以data的形式传给组件,其余的数据以props形式传递给组件

   * 

   */

  const {

    autoClose,

    ...rest

  } = options

 

  const instance = new NotificationConstructor({

    propsData: {

      ...rest

    },

    data: {

      autoClose: autoClose === undefined ? 3000 : autoClose

    }

  })

  instance.id = `notification_${seed++}` // 生成唯一id,用来做删除时使用

  // 通过$mount()不传节点的时候,只是生成了一个$el的对象,但是这个时候还没有真正的插入到DOM节点里面去,此时标签节点已经生成好了

  instance.vm = instance.$mount()

  document.body.appendChild(instance.vm.$el)

 

  // 计算高度

  let verticalOffset = 0

  instances.forEach((item) => {

    verticalOffset += item.$el.offsetHeight + 16 // 每个组件高度间隔16px

  })

  verticalOffset += 16 // 最下面的组件底部距离最底部也有16px的间隙

  instance.verticalOffset = verticalOffset

 

  instances.push(instance)

  return instance.vm

}

 

export default notify

友情提示:使用扩展运算符,需要做如下配置:


安装依赖包


➜  vue-demo npm install babel-preset-stage-2

npm WARN vue-demo@1.0.0 No repository field.

 

+ babel-preset-stage-2@6.24.1

added 13 packages from 1 contributor and audited 8458 packages in 6.963s

found 5 vulnerabilities (2 low, 1 moderate, 2 high)

  run `npm audit fix` to fix them, or `npm audit` for details

➜  vue-demo npm run dev

配置.babelrc文件


{

  "presets": [

    "env",

    "stage-2"

  ],

  "plugins": [

    "transform-vue-jsx"

  ]

}

修改webpack.config.js配置




3.4 点击发送通知按钮后查看效果




3秒后的效果,通知消失了



  • 2021-02-03 16:57:34

    iOS中的动态库和静态库分析

    由于最近研究组件化后调试时二进制映射源码的功能,发现需要对开发中的动态库和静态库需要有一些了解。所以就有了这篇文章,由于只是了解,并没有深入到编译层面,所以本篇文章只是简单了解一些库的知识,并不深入。

  • 2021-02-03 16:58:39

    iOS静态库与动态库的区别与打包

    这篇主要是记录一下 iOS 下静态库与动态库的打包流程,以便以后用到时快速查阅,供自己也供大家学习记录。同时也简述了一下 动态库 与 静态库 的区别。

  • 2021-02-03 16:59:59

    iOS 静态库和动态库全分析

    库就是程序代码的集合,将 N 个文件组织起来,是共享程序代码的一种方式。从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。

  • 2021-02-03 17:01:30

    iOS库 .a与.framework区别

    静态库:连接时完整地拷贝至可执行文件中,被屡次使用就有多份冗余拷贝。 动态库:连接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。

  • 2021-02-03 17:13:58

    iOS - 封装静态库

    静态库:链接时完整的拷贝至可执行文件中,被多次使用就有多份冗余拷贝,.a的静态库 .framework的静态库

  • 2021-02-03 17:16:07

    iOS 中的动态库、静态库和 framework

    首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用。 什么时候我们会用到库呢?一种情况是某些代码需要给别人使用,但是我们不希望别人看到源码,就需要以库的形式进行封装,只暴露出头文件。另外一种情况是,对于某些不会进行大的改动的代码,我们想减少编译的时间,就可以把它打包成库,因为库是已经编译好的二进制了,编译的时候只需要 Link 一下,不会浪费编译时间。

  • 2021-02-03 17:17:53

    iOS 同一个工程下打包不同的app

    应用图标,启动画面,应用启动后的首页都不一样。 有些课程(例如公务员考试和高考)是有目标考试的概念,不同的目标考试大纲是不一样的。拿高考来举例,北京的高考和上海的高考,就有着完全不一样的考试大纲。高考的文科和理科,又有着完全不同的考试科目。 有些课程会有一些自定义的界面,例如高考的应用可以设置昵称,有些课程的真题练习中是有推荐真题模块的,而有些课程又没有。 有些课程有扫描答题卡功能,有些课程有考前冲刺功能,有些课程有大题专项查看功能,而有些课程又没有上述功能。另外还有一些微小细节,但是解决方法和类似,所以就不一一展开说明。

  • 2021-02-04 14:02:30

    window软件界面找不到了跑到屏幕外面去了

    一般可以这样操作,按Alt+空格,然后按M,然后用上下左右键把窗口移动到能看到的地方,再按回车。有些第三方的软件可能不能用,大部分都可以这样做。

  • 2021-02-04 14:08:13

    基于 Electron 的爬虫框架 Nightmare

    Electron 可以让你使用纯 JavaScript 调用 Chrome 丰富的原生的接口来创造桌面应用。你可以把它看作一个专注于桌面应用的 Node.js 的变体,而不是 Web 服务器。其基于浏览器的应用方式可以极方便的做各种响应式的交互,接下来介绍下关于 Electron 上衍生出的框架 Nightmare