vue--组件-实用技能(1)

本文介绍如何使用Vue封装一个全局通知组件,实现类似jQuery的通知效果。通过将组件挂载到Vue原型上,使得通知组件可以在任意组件中通过this.$notify调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对象:notification

目标:达成想jquery一样的代码调用方式。

方法:对象挂在到vue的prototype上,可全局应用


step1:

notification.vue————对象原型

<template>
  <div>
    <transition name="fade" @after-leave="afterLeave" @after-enter="afterEnter">
      <div
        class="notification"
        :style="style"
        v-show="visible"
        @mouseenter="clearTimer"
        @mouseleave="createTimer"
      >
        <span class="content">{{content}}</span>
        <a class="btn" @click="handleClose">{{btn}}</a>
      </div>
    </transition>
  </div>
</template>

<script>
  export default {
    name: 'Notification',
    props: {
      content: {
        type: String,
        required: true
      },
      btn: {
        type: String,
        default: "close"
      }
    },
    data() {
      return {
        visible: true
      }
    },
    computed: {
      style() {
        return {}
      }
    },
    methods: {
      handleClose(e) {
        e.preventDefault()
        this.$emit('close')
      },
      afterLeave() {
        this.$emit('closed')
      },
      afterEnter() {
      },
      clearTimer() {
      },
      createTimer() {
      }
    }
  }
</script>


<style lang="stylus" scoped>
  .notification
    display: inline-flex
    background-color #303030
    color rgba(255, 255, 255, 1)
    align-items center
    padding 20px
    min-width 280px
    box-shadow 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12)
    flex-wrap wrap
    transition all .3s

  .content
    padding 0

  .btn
    color #ff4081
    padding-left 24px
    margin-left auto
    cursor pointer
</style>


复制代码

step2:

function-notification.js ——————扩展notification属性

import Notification from './notification.vue'

export default {
  extends: Notification,
  computed: {
    style() {
      return {
        position: 'fixed',
        right: '20px',
        bottom: `${this.verticalOffset}px`
      }
    }
  },
  mounted() {
    this.createTimer()
  },
  methods: {
    createTimer() {
      if (this.autoClose) {
        this.timer = setTimeout(() => {
          this.visible = false
        }, this.autoClose)
      }
    },
    clearTimer() {
      if (this.timer) {
        clearTimeout(this.timer)
      }
    },
    afterEnter() {
      //debugger
      this.height = this.$el.offsetHeight
    }
  },
  beforeDestroy() {
    if (this.timer) {
      clearTimeout(this.timer)
    }
  },
  data() {
    return {
      verticalOffset: 0,
      autoClose: 3000,
      height: 0,
      visible: false
    }
  }
}
复制代码

step3:

function.js——————对象操作

import Vue from 'vue'
import Component from './func-notification'

const NotificationConstructor = Vue.extend(Component)

const instances = []
let seed = 1

const removeInstance = (instance) => {
  if (!instance) {
    return
  }
  const len = instances.length
  const index = instances.findIndex(inst => instance.id === inst.id)
  instances.splice(index, 1)  //delete
  if (len <= 1) return
  const removeHeight = instance.vm.height
  for (let i = index; i < len - 1; i++) {
    instances[i].verticalHeight =
      parseInt(instances[i].verticalOffset) - removeHeight - 16
  }
}

const notify = (options) => {
  if (Vue.prototype.$isServer) return   // 服务端时,不能做任何操作

  const {autoClose, ...rest} = options

  const instance = new NotificationConstructor({
    propsData: {...rest},
    data: {
      autoClose: autoClose === undefined ? 3000 : autoClose
    }
  })

  const id = `notification_${seed++}`
  instance.id = id
  instance.vm = instance.$mount()
  document.body.appendChild(instance.vm.$el)
  instance.vm.visible = true

  let verticalOffset = 0
  instances.forEach(item => {
    verticalOffset += item.$el.offsetHeight + 16
  })
  verticalOffset += 16
  instance.verticalOffset = verticalOffset
  instances.push(instance)
  instance.vm.$on('closed', () => {
    removeInstance(instance)
    document.body.removeChild(instance.vm.$el)
    instance.vm.$destroy()
  })
  instance.vm.$on('close', () => {
    instance.vm.visible = false
  })
  return instance.vm
}
export default notify
复制代码

step4:

index.js————挂在到原型上

import Notification from './notification.vue'
import Notify from './function'

export default (Vue) => {
  Vue.component(Notification.name, Notification)
  Vue.prototype.$notify = Notify
  //加到prototype上的属性,每个组件都可以通过this.调用
}复制代码


-------------------------------show time,baby!!!------------------------

app.vue

......
<button @click="notify">click me to notify</button>

......

methods: {复制代码
  notify() {
    this.$notify({          //代码式的直接调用,convenient
      content: '关闭提示框内容',
      btn: '关闭'
    })
  }
},复制代码

与vue重点的组件化思想有点差别,但是种极好的一种封装思想。

重点是:非常实用~~~~(不用事先在各个界面定义好控件,随用随调,完美)。类比可封装其他的弹框等控件


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值