vue2 自定义empty指令

主要思路

  1. 定义一个echarts图标,数据为空,image采用base64编码
  2. 图标宽高根据父宽高自适应
  3. 渲染echarts函数,切换清除图例
  4. 定义暂无数据指令

定义option

/**
 * 暂无数据
 * @param {number} width
 * @param {number} height
 * @returns option
 */
function emptyChartOptionFn(width = 150, height = 120) {
  return {
    title: {
      text: `{a|}\n{b|暂无数据}`,
      x: 'center',
      y: 'center',
      itemGap: 0,
      textStyle: {
        rich: {
          a: {
            height,
            width,
            backgroundColor: {
              image:
                'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTU1IiBoZWlnaHQ9IjEyMCIgdmlld0JveD0iMCAwIDE1NSAxMjAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIG9wYWNpdHk9IjAuNiI+CjxyZWN0IHg9IjgyLjU0MyIgeT0iMTIiIHdpZHRoPSI3MCIgaGVpZ2h0PSI5MCIgcng9IjYiIHRyYW5zZm9ybT0icm90YXRlKDYuMDg2NjYgODIuNTQzIDEyKSIgZmlsbD0iI0Y1RjZGQSIgc3Ryb2tlPSIjOEY5QUIyIi8+CjxyZWN0IG9wYWNpdHk9IjAuMiIgeD0iOTMuMzQ5IiB5PSIzMy4yNjU2IiB3aWR0aD0iMTMiIGhlaWdodD0iMiIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKDYuMDg2NjYgOTMuMzQ5IDMzLjI2NTYpIiBmaWxsPSIjOEY5QUIyIi8+CjxyZWN0IHg9IjExMC4yNTMiIHk9IjM1LjA2ODQiIHdpZHRoPSIyNyIgaGVpZ2h0PSIyIiByeD0iMSIgdHJhbnNmb3JtPSJyb3RhdGUoNi4wODY2NiAxMTAuMjUzIDM1LjA2ODQpIiBmaWxsPSIjOEY5QUIyIi8+CjxyZWN0IHg9IjkxLjg2NDYiIHk9IjQ3LjE4NjUiIHdpZHRoPSIzMiIgaGVpZ2h0PSIyIiByeD0iMSIgdHJhbnNmb3JtPSJyb3RhdGUoNi4wODY2NiA5MS44NjQ2IDQ3LjE4NjUpIiBmaWxsPSIjOEY5QUIyIi8+CjxyZWN0IG9wYWNpdHk9IjAuMiIgeD0iMTI3LjY2MiIgeT0iNTEuMDAzOSIgd2lkdGg9IjgiIGhlaWdodD0iMiIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKDYuMDg2NjYgMTI3LjY2MiA1MS4wMDM5KSIgZmlsbD0iIzhGOUFCMiIvPgo8cmVjdCBvcGFjaXR5PSIwLjIiIHg9Ijg4Ljg5NTYiIHk9Ijc1LjAyODgiIHdpZHRoPSIzMi42ODg0IiBoZWlnaHQ9IjIiIHJ4PSIxIiB0cmFuc2Zvcm09InJvdGF0ZSg2LjA4NjY2IDg4Ljg5NTYgNzUuMDI4OCkiIGZpbGw9IiM4RjlBQjIiLz4KPHJlY3QgeD0iOTAuMzgwMSIgeT0iNjEuMTA3OSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIiIHJ4PSIxIiB0cmFuc2Zvcm09InJvdGF0ZSg2LjA4NjY2IDkwLjM4MDEgNjEuMTA3OSkiIGZpbGw9IiM4RjlBQjIiLz4KPHJlY3Qgb3BhY2l0eT0iMC4yIiB4PSIxMTQuMjQ1IiB5PSI2My42NTI4IiB3aWR0aD0iMjAiIGhlaWdodD0iMiIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKDYuMDg2NjYgMTE0LjI0NSA2My42NTI4KSIgZmlsbD0iIzhGOUFCMiIvPgo8L2c+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2RfMjA0MF82NjU5OCkiPgo8cmVjdCB4PSIxNy4zMzQ0IiB5PSIxMDIuNzEiIHdpZHRoPSI3MCIgaGVpZ2h0PSIxMDAiIHJ4PSI2IiB0cmFuc2Zvcm09InJvdGF0ZSgtOTcuNjYzMSAxNy4zMzQ0IDEwMi43MSkiIGZpbGw9IiNGNUY2RkEiIHN0cm9rZT0iIzhGOUFCMiIvPgo8Y2lyY2xlIG9wYWNpdHk9IjAuMiIgY3g9IjMzLjU5NjciIGN5PSI0OC40MjQzIiByPSI4IiB0cmFuc2Zvcm09InJvdGF0ZSgtNy42NjMwOSAzMy41OTY3IDQ4LjQyNDMpIiBzdHJva2U9IiM3QTg1OTkiIHN0cm9rZS13aWR0aD0iMS40Ii8+CjxwYXRoIGQ9Ik0zNC42NjM0IDU2LjM1MjhDMzYuMzYyMSA1Ni4xMjQzIDM3Ljk0MjQgNTUuMzU2MiAzOS4xNzE3IDU0LjE2MThDNDAuNDAwOSA1Mi45Njc0IDQxLjIxNCA1MS40MDk3IDQxLjQ5MTMgNDkuNzE4NEM0MS43Njg1IDQ4LjAyNyA0MS40OTUzIDQ2LjI5MTMgNDAuNzExNyA0NC43NjY5QzM5LjkyODEgNDMuMjQyNSAzOC42NzU3IDQyLjAxMDEgMzcuMTM4OSA0MS4yNTEyQzM1LjYwMjEgNDAuNDkyMyAzMy44NjIyIDQwLjI0NyAzMi4xNzU1IDQwLjU1MTVDMzAuNDg4OCA0MC44NTYgMjguOTQ0NSA0MS42OTQxIDI3Ljc3IDQyLjk0MjRDMjYuNTk1NiA0NC4xOTA4IDI1Ljg1MzEgNDUuNzgzMyAyNS42NTE5IDQ3LjQ4NTRDMjUuNDUwOCA0OS4xODc1IDI1LjgwMTYgNTAuOTA5MiAyNi42NTI3IDUyLjM5NjkiIHN0cm9rZT0iIzhGOUFCMiIgc3Ryb2tlLXdpZHRoPSIyIi8+CjxjaXJjbGUgb3BhY2l0eT0iMC4yIiBjeD0iMzYuMjYzNyIgY3k9IjY4LjI0NTYiIHI9IjUiIHRyYW5zZm9ybT0icm90YXRlKC03LjY2MzA5IDM2LjI2MzcgNjguMjQ1NikiIHN0cm9rZT0iIzdBODU5OSIgc3Ryb2tlLXdpZHRoPSIxLjQiLz4KPHBhdGggZD0iTTM2LjkzMDQgNzMuMjAxQzM3LjkxMDUgNzMuMDY5MSAzOC44Mjk1IDcyLjY0OTYgMzkuNTcxMSA3MS45OTU0QzQwLjMxMjcgNzEuMzQxMyA0MC44NDM4IDcwLjQ4MTkgNDEuMDk3IDY5LjUyNkM0MS4zNTAyIDY4LjU3IDQxLjMxNDMgNjcuNTYwNSA0MC45OTM3IDY2LjYyNUM0MC42NzMyIDY1LjY4OTUgNDAuMDgyNSA2NC44NyAzOS4yOTYyIDY0LjI3MDJDMzguNTA5OSA2My42NzA1IDM3LjU2MzUgNjMuMzE3MyAzNi41NzY1IDYzLjI1NTRDMzUuNTg5NSA2My4xOTM2IDM0LjYwNjQgNjMuNDI1OCAzMy43NTE0IDYzLjkyMjZDMzIuODk2NCA2NC40MTk1IDMyLjIwNzkgNjUuMTU4OCAzMS43NzMgNjYuMDQ3QzMxLjMzODIgNjYuOTM1MSAzMS4xNzY1IDY3LjkzMjMgMzEuMzA4MyA2OC45MTI0IiBzdHJva2U9IiM4RjlBQjIiIHN0cm9rZS13aWR0aD0iMiIvPgo8Y2lyY2xlIG9wYWNpdHk9IjAuMiIgY3g9IjM4LjUzMDUiIGN5PSI4NS4wOTM4IiByPSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNy42NjMwOSAzOC41MzA1IDg1LjA5MzgpIiBzdHJva2U9IiM3QTg1OTkiIHN0cm9rZS13aWR0aD0iMS40Ii8+CjxwYXRoIGQ9Ik00My40ODU5IDg0LjQyN0M0My4zODkgODMuNzA3MSA0My4xMzY0IDgzLjAxNjkgNDIuNzQ1NyA4Mi40MDQ1QzQyLjM1NSA4MS43OTIxIDQxLjgzNTUgODEuMjcyMSA0MS4yMjM0IDgwLjg4MDlDNDAuNjExMyA4MC40ODk3IDM5LjkyMTQgODAuMjM2NSAzOS4yMDE1IDgwLjEzOUMzOC40ODE2IDgwLjA0MTUgMzcuNzQ5MiA4MC4xMDIxIDM3LjA1NTEgODAuMzE2NEMzNi4zNjEgODAuNTMwOCAzNS43MjE5IDgwLjg5MzggMzUuMTgyNCA4MS4zODAzQzM0LjY0MjkgODEuODY2NyAzNC4yMTU4IDgyLjQ2NDkgMzMuOTMxIDgzLjEzMzJDMzMuNjQ2MSA4My44MDE0IDMzLjUxMDMgODQuNTIzNyAzMy41MzMgODUuMjQ5OEMzMy41NTU2IDg1Ljk3NTkgMzMuNzM2MiA4Ni42ODgzIDM0LjA2MjIgODcuMzM3NSIgc3Ryb2tlPSIjOEY5QUIyIiBzdHJva2Utd2lkdGg9IjIiLz4KPHJlY3Qgb3BhY2l0eT0iMC4yIiB4PSI1Ny4wMDA0IiB5PSI1Ny4zODM4IiB3aWR0aD0iMzgiIGhlaWdodD0iMiIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKC03LjY2MzA5IDU3LjAwMDQgNTcuMzgzOCkiIGZpbGw9IiM3QTg1OTkiLz4KPHJlY3Qgb3BhY2l0eT0iMC4yIiB4PSI2MS4wMDA5IiB5PSI4Ny4xMTU3IiB3aWR0aD0iMzgiIGhlaWdodD0iMiIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKC03LjY2MzA5IDYxLjAwMDkgODcuMTE1NykiIGZpbGw9IiM3QTg1OTkiLz4KPHJlY3Qgb3BhY2l0eT0iMC4yIiB4PSI1Ny4wMzk5IiB5PSIzNS4xODAyIiB3aWR0aD0iMiIgaGVpZ2h0PSIyMSIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKC03LjY2MzA5IDU3LjAzOTkgMzUuMTgwMikiIGZpbGw9IiM3QTg1OTkiLz4KPHJlY3Qgb3BhY2l0eT0iMC4yIiB4PSI1OC4wNjcxIiB5PSI2NS4zMTIiIHdpZHRoPSIyIiBoZWlnaHQ9IjI0IiByeD0iMSIgdHJhbnNmb3JtPSJyb3RhdGUoLTcuNjYzMDkgNTguMDY3MSA2NS4zMTIpIiBmaWxsPSIjN0E4NTk5Ii8+CjxyZWN0IG9wYWNpdHk9IjAuMiIgeD0iNjYuOTUwNyIgeT0iMzMuODQ2NyIgd2lkdGg9IjIiIGhlaWdodD0iMjEiIHJ4PSIxIiB0cmFuc2Zvcm09InJvdGF0ZSgtNy42NjMwOSA2Ni45NTA3IDMzLjg0NjcpIiBmaWxsPSIjN0E4NTk5Ii8+CjxyZWN0IG9wYWNpdHk9IjAuMiIgeD0iNzYuODYxMyIgeT0iMzIuNTEzMiIgd2lkdGg9IjIiIGhlaWdodD0iMjEiIHJ4PSIxIiB0cmFuc2Zvcm09InJvdGF0ZSgtNy42NjMwOSA3Ni44NjEzIDMyLjUxMzIpIiBmaWxsPSIjN0E4NTk5Ii8+CjxyZWN0IG9wYWNpdHk9IjAuMiIgeD0iODYuNzcyMSIgeT0iMzEuMTc5NyIgd2lkdGg9IjIiIGhlaWdodD0iMjEiIHJ4PSIxIiB0cmFuc2Zvcm09InJvdGF0ZSgtNy42NjMwOSA4Ni43NzIxIDMxLjE3OTcpIiBmaWxsPSIjN0E4NTk5Ii8+CjxyZWN0IHg9IjU4Ljc3MzQiIHk9IjQ4LjA2NCIgd2lkdGg9IjIiIGhlaWdodD0iOCIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKC03LjY2MzA5IDU4Ljc3MzQgNDguMDY0KSIgZmlsbD0iIzhGOUFCMiIvPgo8cmVjdCB4PSI2Ny40ODQiIHk9IjM3LjgxMSIgd2lkdGg9IjIiIGhlaWdodD0iMTciIHJ4PSIxIiB0cmFuc2Zvcm09InJvdGF0ZSgtNy42NjMwOSA2Ny40ODQgMzcuODExKSIgZmlsbD0iIzhGOUFCMiIvPgo8cmVjdCB4PSI3OC4xOTQ4IiB5PSI0Mi40MjM4IiB3aWR0aD0iMiIgaGVpZ2h0PSIxMSIgcng9IjEiIHRyYW5zZm9ybT0icm90YXRlKC03LjY2MzA5IDc4LjE5NDggNDIuNDIzOCkiIGZpbGw9IiM4RjlBQjIiLz4KPHJlY3QgeD0iODYuOTA1NCIgeT0iMzIuMTcwOSIgd2lkdGg9IjIiIGhlaWdodD0iMjAiIHJ4PSIxIiB0cmFuc2Zvcm09InJvdGF0ZSgtNy42NjMwOSA4Ni45MDU0IDMyLjE3MDkpIiBmaWxsPSIjOEY5QUIyIi8+CjxwYXRoIGQ9Ik02NC41NjUgODMuNjA4OUw3MS4xMzk3IDczLjQzMkw4NS41MzQ4IDgwLjc4NzVMOTIuMzQ3NCA3Ni4wNjk0TDk1LjAwMzQgNjIuMzYwMyIgc3Ryb2tlPSIjOEY5QUIyIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L2c+CjxkZWZzPgo8ZmlsdGVyIGlkPSJmaWx0ZXIwX2RfMjA0MF82NjU5OCIgeD0iMC4yNDU3MjgiIHk9IjEyLjI0NjEiIHdpZHRoPSIxMjcuOTUiIGhlaWdodD0iMTAyLjIxOCIgZmlsdGVyVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiPgo8ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPgo8ZmVDb2xvck1hdHJpeCBpbj0iU291cmNlQWxwaGEiIHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAxMjcgMCIgcmVzdWx0PSJoYXJkQWxwaGEiLz4KPGZlT2Zmc2V0IGR4PSIyIiBkeT0iMiIvPgo8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI1Ii8+CjxmZUNvbXBvc2l0ZSBpbjI9ImhhcmRBbHBoYSIgb3BlcmF0b3I9Im91dCIvPgo8ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMC4xNSAwIi8+CjxmZUJsZW5kIG1vZGU9Im5vcm1hbCIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0iZWZmZWN0MV9kcm9wU2hhZG93XzIwNDBfNjY1OTgiLz4KPGZlQmxlbmQgbW9kZT0ibm9ybWFsIiBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3dfMjA0MF82NjU5OCIgcmVzdWx0PSJzaGFwZSIvPgo8L2ZpbHRlcj4KPC9kZWZzPgo8L3N2Zz4K',
            },
          },
          b: {
            verticalAlign: 'top',
            fontSize: 12,
            lineHeight: 18,
            color: '#686E7C',
          },
        },
      },
      subtextStyle: {
        fontSize: 12,
      },
    },
  }
}

自适配宽高

const getEmptyWH = el => {
  let width = 150
  let height = 120

  // 宽度不够
  if (el.clientWidth < 150) {
    let radio = 120 / 150
    width = el.clientWidth
    height = width * radio
  }
  // 高度不够
  if (el.clientHeight < 120) {
    let radio = 150 / 120
    height = el.clientHeight - 20
    width = height * radio
  }
  return {
    width,
    height,
  }
}

渲染echarts图标至el

const emptyChartFn = el => {
  //初始化echart
  let myChart = Vue.prototype.$echarts.init(el, 'light', {
    height: 'auto',
    width: 'auto',
  })

  const { width, height } = getEmptyWH(el)
  myChart.setOption(optionFn(width, height))

  // myChart绑定到el上,方便后续调用
  el.myChart = myChart
  el.showLoading = myChart.showLoading
  el.hideLoading = myChart.hideLoading
  // 监听屏幕变化
  el.debounceResize = debounce(() => {
    const { width, height } = getEmptyWH(el)
    // 清空当前实例
    el.myChart.clear()
    // 重新绘制
    el.myChart.setOption(optionFn(width, height))
    // 必须加上resize,否则不起作用
    el.myChart.resize({
      animation: {
        duration: 200,
      },
    })
  }, 500)
  // window.addEventListener('resize', el.debounceResize)
  const observer = new ResizeObserver(el.debounceResize)
  observer.observe(el)
  el._observer = observer
}

定义暂无数据指令

// 暂无数据指令
const emptyChart = {
  inserted(el, binding, vnode) {
    const isEmpty = binding.value
    if (!isEmpty) {
      return
    }

    Vue.nextTick(() => {
      emptyChartFn(el)
    })
  },
  update(el, binding, vnode) {
    const isEmpty = binding.value
    if (isEmpty) {
      let myChart = el?.myChart
      if (!myChart) {
        emptyChartFn(el)
      } else {
        myChart.clear()
        emptyChartFn(el)
      }
    }
  },
  //指令卸载的时候去除window事件监听
  unbind(el, binding, vnode) {
    // window.removeEventListener('resize', el.debounceResize)
    const observer = el._observer
    if (observer) {
      observer.unobserve(el)
      delete el._observer
    }
  },
}

注册指令

Vue.directive('emptyChart', emptyChart)

使用

<div v-empty-chart="isEmpty" class="h-full pt-6"></div>

效果

在这里插入图片描述

Vue.js 2中,自定义指令是一种扩展Vue实例功能的方式。根据引用,自定义指令可以分为组件私有自定义指令和项目全局自定义指令。组件私有自定义指令仅在特定组件中可用,而项目全局自定义指令可以在整个项目中使用。 自定义指令的定义方式与过滤器的定义方式类似。可以通过在Vue实例的directives选项中定义指令或在组件的directives选项中定义指令。具体的例子如引用所示,在任意组件中使用v-color指令。 在指令的定义中,可以通过bind和update函数来实现指令所需的逻辑。bind函数在指令被绑定到元素时调用,可以进行初始化设置。update函数在指令所在元素的值发生变化时调用,可以响应数据的变化并做出相应的操作,如引用所述。 总结来说,Vue.js 2中的自定义指令是一种可以扩展Vue实例功能的方式,可以在组件私有或项目全局范围内使用。可以通过定义指令和实现相应的逻辑来实现自定义指令的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [vue2自定义指令方式](https://blog.csdn.net/qq_40639028/article/details/120145794)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值