VueJS自定义组件之弹窗组件和树形组件

弹窗组件

这类组件的特点是在当前Vue实例之外存在,通常挂载与body,上在使用element-ui弹窗组件的时候,我们可以看到这一点:
在这里插入图片描述
并且它们是通过JS动态创建的,不需要在任何组件中声明。接下来我们看具体代码实现。

create.js

创建一个js文件,用来创建弹窗实例

import Vue from 'vue'
export default function create (comp, props) {
  const app = new Vue({
    render (h) {
      return h(comp, { props })
    }
  }).$mount()
  // app.$el为该虚拟DOM的真实DOM
  document.body.appendChild(app.$el)
  // 销毁
  const com = app.$children[0]
  com.remove = function () {
    document.body.removeChild(app.$el)
    app.$destroy()
  }
  return com
}

默认导出一个创建弹窗组件实例的方法,入参1为需要展示的弹窗组件,入参2为该组件的配置对象。首先通过render函数将组件转换成vNode,由于不能通过$mount将组件直接挂载到body上,所以需要我们手动挂载,document.body.appendChild(app.$el),并且为该组件实例添加移除销毁的方法,避免内存泄漏。

模板转换成浏览器认识的HTML过程,
1、template->AST render(compile解析template)
2、AST render->vNode (render函数方法运行)
3、VNode->DOM (vDom.patch)

KNotice.vue

需要展示的弹窗组件

<template>
  <div class="notice" v-if="isShow">
    <h3>{{ title }}</h3>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: {
    title: { type: String },
    message: { type: String },
    duration: { type: Number, default: 2000 }
  },
  data () {
    return {
      isShow: false
    }
  },
  methods: {
    show () {
      this.isShow = true
      setTimeout(() => {
        this.hide()
      }, this.duration)
    },
    hide () {
      this.isShow = false
      this.remove()
    }
  }
}
</script>

<style lang="scss">
.notice {
  position: absolute;
  top: 20px;
  right: 0;
  left: 0;
  margin: auto;
  width: 300px;
  height: 300px;
  background: #ff00ff;
}
</style>

App.vue

使用弹窗组件

<template>
  <div id="app">
    <button @click="clickHandle">click</button>
</template>

<script>
import create from './utils/create'
import KNotice from './components/notice/KNotice'
export default {
  name: 'App',
  methods: {
    clickHandle () {
      const notice = create(KNotice, {
        title: 'title',
        message: 'this is mesage',
        duration: 1000
      })
      notice.show()
    },
  }
}
</script>

<style lang="scss"></style>

效果图

在这里插入图片描述

树形组件

树形组件是典型的递归组件,像element-ui中的菜单组件都是这一类组件的实现

tree.vue

<template>
  <div>
    <li>
      <p @click="toggle">
        {{ model.title }}
        <span v-if="isFolder">[{{ open ? "-" : "+" }}]</span>
      </p>
      <ul v-show="open" v-if="isFolder">
        <item v-for="(item,index) in model.children" :key="index" :model="item"> </item>
      </ul>
    </li>
  </div>
</template>

<script>
export default {
  name: 'item',
  props: {
    model: {
      type: Object
    }
  },
  data () {
    return {
      open: false
    }
  },
  computed: {
    isFolder () {
      return this.model.children && this.model.children.length
    }
  },
  methods: {
    toggle () {
      if (this.isFolder) {
        this.open = !this.open
      }
    }
  }
}
</script>

<style lang="scss" scoped></style>

App.vue

<template>
  <div id="app">
    <ul>
      <item :model="model"></item>
    </ul>
  </div>
</template>

<script>
import Item from './components/tree'
export default {
  name: 'App',
  components: {
    Item
  },
  data () {
    return {
      list: {
        id: 1,
        title: '递归组件1',
        children: [
          {
            id: 2,
            title: '递归组件2',
            children: [
              {
                id: 4,
                title: '递归组件4'
              },
              {
                id: 5,
                title: '递归组件5'
              }
            ]
          },
          {
            id: 3,
            title: '递归组件3'
          }
        ]
      },
      model: {
        title: 'a',
        children: [
          {
            title: 'b'
          },
          {
            title: 'c',
            children: [
              {
                title: 'cc'
              },
              {
                title: 'dd'
              }
            ]
          }
        ]
      }
    }
  },
 }
</script>

<style lang="scss"></style>

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以为您提供一些关于用Vue.js封装自定义水印组件的指导。 首先,您可以使用Vue.js组件化思想来封装这个自定义水印组件。可以创建一个名为"Watermark"的Vue组件,在其包含一个img标签用于显示图片,以及一个canvas标签用于绘制水印。在created生命周期,获取到图片的资源并将其绘制到canvas上,接着在mounted生命周期绘制水印,并使用canvas.toDataURL()获取带有水印的图片地址。 以下是一个示例代码,供您参考: ```html <template> <div> <canvas ref="canvas" width="300" height="200"></canvas> <img :src="imageWithWatermark"/> </div> </template> <script> export default { props: { imageSrc: String, // 传入图片地址 watermarkText: String // 传入水印文字 }, data() { return { imageWithWatermark: "" // 带有水印的图片地址 }; }, created() { // 获取图片资源,初始化canvas this.image = new Image(); this.image.src = this.imageSrc; this.image.onload = () => { this.ctx = this.$refs.canvas.getContext("2d"); this.ctx.drawImage(this.image, 0, 0, this.$refs.canvas.width, this.$refs.canvas.height); }; }, mounted() { // 绘制水印 this.ctx.font = "20px serif"; this.ctx.fillStyle = "rgba(100, 100, 100, 0.5)"; this.ctx.rotate(-Math.PI / 4); this.ctx.fillText(this.watermarkText, -120, 150); // 获取带有水印的图片 this.imageWithWatermark = this.$refs.canvas.toDataURL(); } }; </script> ``` 在使用时,只需要传入图片地址和水印文字即可: ```html <template> <div> <Watermark :imageSrc="imageSrc" watermarkText="Custom Watermark"/> </div> </template> <script> import Watermark from "@/components/Watermark"; export default { components: { Watermark }, data() { return { imageSrc: "http://example.com/image.jpg" // 图片地址 }; } }; </script> ``` 当然,以上代码只是示例,实际使用时还可以进行优化和扩展,例如自定义水印的颜色、位置等。希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值