在Vue将第三方JS库封装为组件使用

第三方JS库地址:https://github.com/inorganik/CountUp.js

使用NPM进行安装:

npm install --save countup

根据官方回答,CountUp.js是一个无依赖,轻量级的Javascript类,可用于快速创建以更有趣的方式显示数值数据的动画。

在代码开始之前,先补充几个Vue.js的基础知识:

1.this._uid的使用:每个组件都有一个唯一的id,可以作为this._uid访问。

具体使用场景:组件是要在多个地方多次使用 ,而一个页面上每一个id值都要互不相同。如果id值固定的话 在多次使用这个组件的时候就会出现多个元素的id都是同一个值。

2.计算属性computed

设计它的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。

使用官网的例子通俗易懂:

<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。所以,对于任何复杂逻辑,你都应当使用计算属性。

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

2.1计算属性和方法的区别:

        计算属性是基于它们的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会重新求值,两者的计算结果完全相同

2.1计算属性和侦听属性(Watch)的区别:

   计算属性更适合于通常的场景,如下代码:

<div id="demo">{{ fullName }}</div>
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

若改为计算属性则可以缩减代码量:

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

        虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

3.组件的默认值写法。

当组件的属性类型时Object或者Array时,需要使用工厂函数返回'的默认值(注意括号):

props: {
  yourProp: {
    type: Object,
    default: () => ({
      param: value,
      param2: value,
    }),
  },
}
props: {
  arr: {
    type: Array,
    default: function () { return [] }
  }
}
//ES6写法
props: {
  arr: {
    type: Array,
    default: () => []
  }
}

4.在Vue中获取并操作dom:

要在mounted中使用,因为只有在执行mounted的时候,vue已经渲染了dom节点,这个时候是可以获取dom节点的,vue中尽量不去操作dom元素,选用ref操作属性获取。

mounted(){//这里必须是mouted钩子
    this.title = document.querySelector('#footer-box-title');
    this.title.style.color = "#ff0000";
}
<button ref="btn">获取ref</button>
this.$refs.btn.style.backgroundColor="#ff0000"

 5.理解Vue中的nextTick

下面回到正题:

代码目录结构:

./src/components/count-to/count-to.less:

  .count-to-number{
    color: palevioletred;
  } 

./src/components/count-to/count-to.vue:

<template>
  <div>
    <slot name="left"></slot><span ref="number" :class="countClass" :id="eleId"></span><slot name="right"></slot>
  </div>
</template>
<script>
import CountUp from 'countup'
export default {
  name: 'CountTo',
  computed: {
    eleId () {
      return `count_up_${this._uid}`
    },
    countClass () {
      return [
        'count-to-number',
        this.className
      ]
    }
  },
  data () {
    return {
      counter: {}
    }
  },
  props: {
    /**
     * @description 起始值
     */
    startVal: {
      type: Number,
      default: 0
    },
    /**
     * @description 最终值
     */
    endVal: {
      type: Number,
      required: true
    },
    /**
     * @description 小数点后保留几位小数
     */
    decimals: {
      type: Number,
      default: 0
    },
    /**
     * @description 动画延迟开始时间
     */
    delay: {
      type: Number,
      default: 0
    },
    /**
     * @description 渐变时长
     */
    duration: {
      type: Number,
      default: 1
    },
    /**
     * @description 是否使用变速效果
     */
    useEasing: {
      type: Boolean,
      default: false
    },
    /**
     * @description 是否使用变速效果
     */
    useGrouping: {
      type: Boolean,
      default: true
    },
    /**
     * @description 分组符号
     */
    separator: {
      type: String,
      default: ','
    },
    /**
     * @description 整数和小数分割符号
     */
    decimal: {
      type: String,
      default: '.'
    },
    className: {
      type: String,
      default: ''
    }
  },
  methods: {
    getCount () {
      return this.$refs.number.innerText
    },
    emitEndEvent () {
      setTimeout(() => {
        this.$nextTick(() => {
          this.$emit('on-animation-end', Number(this.getCount()))
        })
      }, this.duration * 1000 + 5)
    }
  },
  watch: {
    endVal (newVal, oldVal) {
      this.counter.update(newVal)
      this.emitEndEvent()
    }
  },
  mounted () {
    this.$nextTick(() => {
      this.counter = new CountUp(this.eleId, this.startVal, this.endVal, this.decimals, this.duration, {
        useEasing: this.useEasing,
        useGrouping: this.useGrouping,
        separator: this.separator,
        decimal: this.decimal
      })
      setTimeout(() => {
        this.counter.start()
        this.emitEndEvent()
      }, this.delay)
    })
  }
}
</script>
<style lang="less">
@import './count-to.less';
</style>

 ./src/components/count-to/index.js:

import CountTo from './count-to.vue'
export default CountTo

  ./src/router/router.js增加对count-to.vue的路由:

{
    path: '/count-to',
    name: 'count_to',
    component: () => import('@/views/count-to.vue')
}

 ./src/views/count-to.vue:

<template>
  <div>
    <count-to ref="countTo" :end-val="endVal" @on-animation-end="handleEnd">
      <span slot="left">总金额:</span>
      <span slot="right">元</span>
    </count-to>
    <button @click="getNumber">获取数值</button>
    <button @click="up">更新值</button>
  </div>
</template>
<script>
import CountTo from "@/components/count-to";
export default {
  name: "count_to",
  components: {
    CountTo
  },
  data() {
    return {
      endVal: 100
    };
  },
  methods: {
    getNumber() {
      this.$refs.countTo.getCount();
    },
    up() {
      this.endVal += Math.random() * 100;
    },
    handleEnd(endVal) {
      console.log("end -> ", endVal);
    }
  }
};
</script>

运行效果:

猜你喜欢

转载自www.cnblogs.com/qicao/p/10805715.html