vue3.0用render创建button组件

本文介绍了作者如何基于navie-ui的button源码和tailwindcss创建一个自定义的Vue按钮组件,支持加载、禁用状态,并提供了多种主题颜色和尺寸配置。组件允许在按钮中自由放置内容,具有灵活的样式覆盖功能,以适应不同的设计需求。

一、前言

2021年8月13日耗费一天时间按照navie-ui的button源码,自己写了一个button组件,css使用的tailwindcss,可以自己重写。那个myload是另一个组件,主要就是加载状态的图标。

二、代码

<script>
import {defineComponent,h} from "vue";
import myload from "../myload/index.vue"
export default defineComponent({
  name: "",
  props:{
    loading:{
      default:false,
      type:Boolean,
    },
    disabled:{
      default:false,
      type:Boolean,
    },
  },
  setup() {
    return {}
  },
  methods:{
  },
  render(){
    return h('button',{
      class:{
        "min-w-28":true,
        "relative":true,
        "px-3":true,
        "py-2":true,
        "h-12":true,
        "text-gray-600":true,
        "rounded":true,
        "border":true,
        "border-gray-200":true,
        "hover:border-blue-600":!this.$props.loading&&!this.$props.disabled,
        "hover:text-gray-50":!this.$props.disabled,
        "hover:bg-blue-500":!this.$props.disabled,
        "active:bg-gray-400":true,
        "flex":true,
        "justify-center":true,
        "items-center":true,
        "cursor-not-allowed":this.$props.disabled,
        "text-black":this.$props.disabled,
        "bg-gray-200":this.$props.disabled,
        "bg-opacity-50":this.$props.disabled,
      },disabled: this.$props.disabled,
    },[h("span",{class:{"z-0":true}},this.$slots.default())],this.$props.loading?h("div",{
      class:{"absolute":true,"inset-0":true,"bg-white":true,"flex":true,"justify-center":true,"items-center":true,"z-50":true}
    },this.$slots.loadicon||h(myload,{},"")):null)
  },
  components: {},
})
</script>

<style scoped>
</style>

这是第一版,只实现了loading和disable状态

三、原因和目的

1.为什么要自己做按钮组件:
现成的按钮组件有很多状态,能适应很多情况,但不能适应所有情况,所以我需要修改他们的按钮组件,但是那些组件可修改的地方并不多,所以需要自己定制。
2.我想要的组件长什么样
a.默认拥有loading和disabled两种状态
b.中间随意放置文字图标等
c.圆角和圆形功能放到外层实现
d.背景透明、白色、主题颜色
e.高度和宽度主要由外层设置
f.边框随主题颜色
g.文字大小随尺寸
h.文字颜色随主题颜色
i.hover和active随主题颜色
j.被点击后的激活状态样式可以被外层覆盖
j.设置否决属性,一票否决所有设置,全部由外层定制

四、增加阻止点击事件冒泡和一些主题颜色配置

<script>
import {defineComponent, h, ref,watch} from "vue";
import myload from "../myload/index.vue"

export default defineComponent({
  name: "",
  props: {
    loading: {
      default: false,
      type: Boolean,
    },
    disabled: {
      default: false,
      type: Boolean,
    },
    // 组件大小,可选large,big,middle,small,mini
    size: {
      type: String,
      default: "middle",
    },
    // 主题,可选red,blue,green,default,text,yellow,purple
    type: {
      type: String,
      default: "default",
    },
    // 默认圆角,直角需要传递false
    rounded:{
      type:Boolean,
      default:true,
    },
  },
  setup(prop, content) {
    const classlist = ref({})
    const init = () => {
      switch (prop.size) {
        case "large":
          classlist.value = Object.assign(classlist.value, {"w-40": true, "h-18": true, "text-5xl": true})
          break
        case "big":
          classlist.value = Object.assign(classlist.value, {"w-30": true, "h-12": true, "text-4xl": true})
          break
        case "middle":
          classlist.value = Object.assign(classlist.value, {"w-20": true, "h-8": true, "text-3xl": true})
          break
        case "small":
          classlist.value = Object.assign(classlist.value, {"w-10": true, "h-5": true, "text-xl": true})
          break
        case "mini":
          classlist.value = Object.assign(classlist.value, {"w-5": true, "h-2": true, "text-ssss": true})
          break
      }
      switch (prop.type) {
        case "default":
          classlist.value = Object.assign(classlist.value, {
            // 正常状态下,黑色文字和边框,白色背景
            "border": true,
            "border-gray-500": true,
            "text-gray-500": true,
            "bg-white": true,
            // 鼠标覆盖后,文字和边框变蓝
            "over:border-2": !prop.disabled,
            "hover:border-blue-400": !prop.disabled,
            "hover:text-blue-400": !prop.disabled,
            // 点击后,外轮廓变蓝
            "active:ring-1":  !prop.disabled,
            "active:ring-blue-400":  !prop.disabled,
          })
          break
        case "red":
          classlist.value = Object.assign(classlist.value, {
            // 正常状态下,白色文字,红色背景,没有边框
            "text-white": true,
            "bg-red-400": true,
            // 鼠标覆盖后,背景颜色加深
            "hover:bg-red-500": !prop.disabled,
            // 点击后,外轮廓变红
            "active:ring-1":  !prop.disabled,
            "active:ring-red-400":  !prop.disabled,
          })
          break
        case "blue":
          classlist.value = Object.assign(classlist.value, {
            // 正常状态下,白色文字,蓝色背景,没有边框
            "text-white": true,
            "bg-blue-400": true,
            // 鼠标覆盖后,背景颜色加深
            "hover:bg-blue-500": !prop.disabled,
            // 点击后,外轮廓变蓝
            "active:ring-1":  !prop.disabled,
            "active:ring-blue-400":  !prop.disabled,
          })
          break
        case "green":
          classlist.value = Object.assign(classlist.value, {
            // 正常状态下,白色文字,绿色背景,没有边框
            "text-white": true,
            "bg-green-400": true,
            // 鼠标覆盖后,背景颜色加深
            "hover:bg-green-500": !prop.disabled,
            // 点击后,外轮廓变绿
            "active:ring-1":  !prop.disabled,
            "active:ring-green-400":  !prop.disabled,
          })
          break
        case "yellow":
          classlist.value = Object.assign(classlist.value, {
            // 正常状态下,白色文字,黄色背景,没有边框
            "text-white": true,
            "bg-yellow-400": true,
            // 鼠标覆盖后,背景颜色加深
            "hover:bg-yellow-500": !prop.disabled,
            // 点击后,外轮廓变黄
            "active:ring-1":  !prop.disabled,
            "active:ring-yellow-400":  !prop.disabled,
          })
          break
        case "purple":
          classlist.value = Object.assign(classlist.value, {
            // 正常状态下,白色文字,紫色背景,没有边框
            "text-white": true,
            "bg-Purple-400": true,
            // 鼠标覆盖后,背景颜色加深
            "hover:bg-Purple-500": !prop.disabled,
            // 点击后,外轮廓变紫
            "active:ring-1": !prop.disabled,
            "active:ring-Purple-400":  !prop.disabled,
          })
          break
        case "text":
          classlist.value = Object.assign(classlist.value, {
            // 正常状态下,黑色文字,透明背景,没有边框
            "text-gray-600": true,
            // 鼠标覆盖后,文字变红
            "hover:text-red-500": !prop.disabled,
            // 点击后,文字变蓝
            "active:text-blue-400": !prop.disabled,
          })
          break
      }
    }
    watch(()=>prop.disabled,()=>{
      init()
    })
    // 开启loading状态或者disabled状态时,阻止点击事件冒泡
    const loadclick=(e)=>{
      if(prop.loading || prop.loading){
        e.stopPropagation();
      }
    }
    // 初始化区域
    init()
    return {
      classlist,
      loadclick,
    }
  },
  render() {
    return h('button', {
      class: {
        // 基础属性区域
        "min-w-28": true,
        "relative": true,
        "px-3": true,
        "py-2": true,
        "h-12": true,
        "border": true,
        "flex": true,
        "rounded":true,
        // 主题属性区域
        ...this.classlist,
        // loading和disabled属性区域
        "justify-center": true,
        "items-center": true,
        "cursor-not-allowed": this.$props.disabled,
        "text-black": this.$props.disabled,
        "bg-gray-200": this.$props.disabled,
        "bg-opacity-50": this.$props.disabled,
      }, disabled: this.$props.disabled,onClick:this.loadclick,
    }, [h("span", {class: {"z-0": true}}, this.$slots.default())], this.$props.loading ? h("div", {
      class: {
        "absolute": true,
        "inset-0": true,
        "bg-white": true,
        "flex": true,
        "justify-center": true,
        "items-center": true,
        "z-50": true
      },onClick:this.loadclick,
    }, this.$slots.loadicon || h(myload, {}, "")) : null)
  },
  components: {},
})
</script>

<style scoped>

</style>

五.添加透明背景

<script>
import {defineComponent, h, ref,watch} from "vue";
import myload from "../myload/index.vue"

export default defineComponent({
  name: "",
  props: {
    loading: {
      default: false,
      type: Boolean,
    },
    disabled: {
      default: false,
      type: Boolean,
    },
    // 组件大小,可选large,big,middle,small,mini
    size: {
      type: String,
      default: "middle",
    },
    // 主题,可选red,blue,green,default,text,yellow,purple
    type: {
      type: String,
      default: "default",
    },
    // 默认圆角,直角需要传递false
    rounded:{
      type:Boolean,
      default:true,
    },
    // 背景透明
    ghost:{
      default:false,
      type:Boolean,
    },
  },
  setup(prop, content) {
    const classlist = ref({})
    const init = () => {
      switch (prop.size) {
        case "large":
          classlist.value = Object.assign(classlist.value, {"min-w-36": true, "h-18": true, "text-4xl": true,"p-2":true,})
          break
        case "big":
          classlist.value = Object.assign(classlist.value, {"min-w-30": true, "h-14": true, "text-2xl": true,"p-2":true,})
          break
        case "middle":
          classlist.value = Object.assign(classlist.value, {"min-w-20": true, "h-12": true, "text-xl": true,"p-1":true,})
          break
        case "small":
          classlist.value = Object.assign(classlist.value, {"min-w-10": true, "h-9": true, "text-base": true,"p-1":true,})
          break
        case "mini":
          classlist.value = Object.assign(classlist.value, {"min-w-5": true, "h-6": true, "text-ss": true,"p-1":true,})
          break
      }
      switch (prop.type) {
        case "default":
          if(prop.ghost){
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,黑色文字和边框,白色背景
              "border": true,
              "border-gray-500": true,
              "text-gray-500": true,
              "bg-white": true,
              // 鼠标覆盖后,文字和边框变蓝
              "over:border-2": !prop.disabled,
              "hover:border-blue-400": !prop.disabled,
              "hover:text-blue-400": !prop.disabled,
              // 点击后,外轮廓变蓝
              "active:ring-2":  !prop.disabled,
              "active:ring-blue-400":  !prop.disabled,
              "bg-opacity-0":true,
            })
          }else{
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,黑色文字和边框,白色背景
              "border": true,
              "border-gray-500": true,
              "text-gray-500": true,
              "bg-white": true,
              // 鼠标覆盖后,文字和边框变蓝
              "over:border-2": !prop.disabled,
              "hover:border-blue-400": !prop.disabled,
              "hover:text-blue-400": !prop.disabled,
              // 点击后,外轮廓变蓝
              "active:ring-2":  !prop.disabled,
              "active:ring-blue-400":  !prop.disabled,
            })
          }
          break
        case "red":
          if(prop.ghost){
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,红色背景,没有边框
              "text-red-400": true,
              "bg-red-400": true,
              "border": true,
              "border-red-400": true,
              "bg-opacity-0":true,
              // 鼠标覆盖后,背景颜色加深
              "hover:text-red-500": !prop.disabled,
              "hover:border-red-500": !prop.disabled,
              // 点击后,外轮廓变红
              "active:ring-2":  !prop.disabled,
              "active:ring-red-300":  !prop.disabled,
            })
          }else{
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,红色背景,没有边框
              "text-white": true,
              "bg-red-400": true,
              "border": true,
              "border-red-400": true,
              // 鼠标覆盖后,背景颜色加深
              "hover:bg-red-500": !prop.disabled,
              "hover:border-red-500": !prop.disabled,
              // 点击后,外轮廓变红
              "active:ring-2":  !prop.disabled,
              "active:ring-red-300":  !prop.disabled,
            })
          }
          break
        case "blue":
          if(prop.ghost){
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,蓝色背景,没有边框
              "text-blue-400": true,
              "bg-blue-400": true,
              "border": true,
              "border-blue-400": true,
              "bg-opacity-0":true,
              // 鼠标覆盖后,背景颜色加深
              "hover:text-blue-500": !prop.disabled,
              "hover:border-blue-500": !prop.disabled,
              // 点击后,外轮廓变蓝
              "active:ring-2":  !prop.disabled,
              "active:ring-blue-400":  !prop.disabled,
            })
          }else{
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,蓝色背景,没有边框
              "text-white": true,
              "bg-blue-400": true,
              "border": true,
              "border-blue-400": true,
              // 鼠标覆盖后,背景颜色加深
              "hover:bg-blue-500": !prop.disabled,
              "hover:border-blue-500": !prop.disabled,
              // 点击后,外轮廓变蓝
              "active:ring-2":  !prop.disabled,
              "active:ring-blue-400":  !prop.disabled,
            })
          }
          break
        case "green":
          if(prop.ghost){
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,绿色背景,没有边框
              "text-green-400": true,
              "bg-green-400": true,
              "border": true,
              "border-green-400": true,
              "bg-opacity-0":true,
              // 鼠标覆盖后,背景颜色加深
              "hover:text-green-500": !prop.disabled,
              "hover:border-green-500": !prop.disabled,
              // 点击后,外轮廓变绿
              "active:ring-2":  !prop.disabled,
              "active:ring-green-400":  !prop.disabled,
            })
          }else{
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,绿色背景,没有边框
              "text-white": true,
              "bg-green-400": true,
              "border": true,
              "border-green-400": true,
              // 鼠标覆盖后,背景颜色加深
              "hover:bg-green-500": !prop.disabled,
              "hover:border-green-500": !prop.disabled,
              // 点击后,外轮廓变绿
              "active:ring-2":  !prop.disabled,
              "active:ring-green-400":  !prop.disabled,
            })
          }
          break
        case "yellow":
          if(prop.ghost){
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,黄色背景,没有边框
              "text-yellow-400": true,
              "bg-yellow-400": true,
              "border": true,
              "border-yellow-400": true,
              "bg-opacity-0":true,
              // 鼠标覆盖后,背景颜色加深
              "hover:text-yellow-500": !prop.disabled,
              "hover:border-yellow-500": !prop.disabled,
              // 点击后,外轮廓变黄
              "active:ring-2":  !prop.disabled,
              "active:ring-yellow-400":  !prop.disabled,
            })
          }else{
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,黄色背景,没有边框
              "text-white": true,
              "bg-yellow-400": true,
              "border": true,
              "border-yellow-400": true,
              // 鼠标覆盖后,背景颜色加深
              "hover:bg-yellow-500": !prop.disabled,
              "hover:border-yellow-500": !prop.disabled,
              // 点击后,外轮廓变黄
              "active:ring-2":  !prop.disabled,
              "active:ring-yellow-400":  !prop.disabled,
            })
          }
          break
        case "purple":
          if(prop.ghost){
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,紫色背景,没有边框
              "text-purple-400": true,
              "bg-purple-400": true,
              "border": true,
              "border-purple-400": true,
              "bg-opacity-0":true,
              // 鼠标覆盖后,背景颜色加深
              "hover:text-purple-500": !prop.disabled,
              "hover:border-purple-500": !prop.disabled,
              // 点击后,外轮廓变紫
              "active:ring-2": !prop.disabled,
              "active:ring-purple-400":  !prop.disabled,
            })
          }else{
            classlist.value = Object.assign(classlist.value, {
              // 正常状态下,白色文字,紫色背景,没有边框
              "text-white": true,
              "bg-purple-400": true,
              "border": true,
              "border-purple-400": true,
              // 鼠标覆盖后,背景颜色加深
              "hover:bg-purple-500": !prop.disabled,
              "hover:border-purple-500": !prop.disabled,
              // 点击后,外轮廓变紫
              "active:ring-2": !prop.disabled,
              "active:ring-purple-400":  !prop.disabled,
            })
          }
          break
        case "text":
          classlist.value = Object.assign(classlist.value, {
            // 正常状态下,黑色文字,透明背景,没有边框
            "text-gray-600": true,
            // 鼠标覆盖后,文字变红
            "hover:text-red-500": !prop.disabled,
            // 点击后,文字变蓝
            "active:text-blue-400": !prop.disabled,
            "bg-opacity-0":true,
          })
          break
      }
      // 将其他元素添加进去,不做了
    }
    watch(()=>prop.disabled,()=>{
      init()
    })
    // 开启loading状态或者disabled状态时,阻止点击事件冒泡
    const loadclick=(e)=>{
      if(prop.loading || prop.loading){
        e.stopPropagation();
      }
    }
    // 初始化区域
    init()
    return {
      classlist,
      loadclick,
    }
  },
  render() {
    return h('button', {
      class: {
        // 基础属性区域
        "relative": true,
        "flex": true,
        "rounded":this.$props.rounded,
        // 主题属性区域
        ...this.classlist,
        // loading和disabled属性区域
        "justify-center": true,
        "items-center": true,
        "cursor-not-allowed": this.$props.disabled,
        "text-black": this.$props.disabled,
        "bg-gray-200": this.$props.disabled,
        "bg-opacity-50": this.$props.disabled,
      }, disabled: this.$props.disabled,onClick:this.loadclick,
    }, [h("span", {class: {"z-0": true}}, this.$slots.default())], this.$props.loading ? h("div", {
      class: {
        "absolute": true,
        "inset-0": true,
        "bg-white": true,
        "flex": true,
        "justify-center": true,
        "items-center": true,
        "z-50": true
      },onClick:this.loadclick,
    }, this.$slots.loadicon || h(myload, {}, "")) : null)
  },
  components: {},
})
</script>

<style scoped>

</style>
要在Vue 3.0中预览PDF,您可以使用PDF.js库。以下是使用PDF.jsVue 3.0中预览PDF文件的步骤: 1. 安装pdfjs-dist: ``` npm install pdfjs-dist --save ``` 2.Vue组件中,使用`pdfjs-dist`加载PDF文件: ```javascript import pdfjsLib from &#39;pdfjs-dist&#39;; export default { name: &#39;PDFViewer&#39;, data() { return { pdf: null, currentPage: 1, totalPages: 0, }; }, methods: { loadPDF() { const loadingTask = pdfjsLib.getDocument(this.src); loadingTask.promise.then((pdf) => { this.pdf = pdf; this.totalPages = pdf.numPages; this.loadPage(this.currentPage); }); }, loadPage(pageNumber) { this.pdf.getPage(pageNumber).then((page) => { const canvas = this.$refs.canvas; const context = canvas.getContext(&#39;2d&#39;); const viewport = page.getViewport({ scale: 1.0 }); const renderContext = { canvasContext: context, viewport: viewport, }; page.render(renderContext); }); this.currentPage = pageNumber; }, nextPage() { if (this.currentPage < this.totalPages) { this.loadPage(this.currentPage + 1); } }, prevPage() { if (this.currentPage > 1) { this.loadPage(this.currentPage - 1); } }, }, mounted() { this.loadPDF(); }, }; ``` 3.Vue组件的模板中,添加用于呈现PDF的`canvas`元素: ```html <template> <div> <canvas ref="canvas"></canvas> <div> <button @click="prevPage">Previous</button> <button @click="nextPage">Next</button> <span>Page {{ currentPage }} of {{ totalPages }}</span> </div> </div> </template> ``` 4.Vue组件的`props`中添加`src`属性,用于指定要加载的PDF文件的URL: ```javascript export default { name: &#39;PDFViewer&#39;, props: { src: { type: String, required: true, }, }, ... }; ``` 现在,您可以使用`PDFViewer`组件来在Vue 3.0中预览PDF文件: ```html <template> <div> <PDFViewer src="http://example.com/myfile.pdf"></PDFViewer> </div> </template> <script> import PDFViewer from &#39;./PDFViewer.vue&#39;; export default { name: &#39;App&#39;, components: { PDFViewer, }, }; </script> ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值