【问题标题】:How to animate a border using JS for a timer card如何使用 JS 为计时器卡设置边框动画
【发布时间】:2020-12-29 04:28:14
【问题描述】:

我有以下计时器卡,用于我正在制作的计时器应用程序,我希望有一个边框慢慢环绕它,因为它类似于此代码笔倒计时。 https://codepen.io/Mamboleoo/pen/zYOJOGb 进度必须由JS控制。

我正在将 VueJS 与 Vuetify 一起使用,这是我拥有的代码。

      <v-col
          cols="12"
         sm="4"
         xs="4" v-for="timer in formattedTimers" :key="timer.id">

    <v-card :class="{jiggle : editmode}" max-width="200" class="mx-auto" outlined>
      <v-list-item three-line>
        <v-list-item-content>
          <div class="headline mb-8 text-center">{{ timer.name }}</div>
          <v-list-item-title class="headline mb-4 text-center">{{ parseTime(timer.timeLeft) }}</v-list-item-title>
        </v-list-item-content>
      </v-list-item>

      <v-card-actions>
        <div v-if="!editmode">
          <v-btn @click="zeroTimer(timer.id)" left>Zero</v-btn>
          <v-btn color="primary" @click="resetTimer(timer.id)" right absolute>Reset</v-btn>
        </div>
        <div v-else>
          <v-btn color="primary" @click="deleteTimer(timer.id)" left>Delete</v-btn>
        </div>
      </v-card-actions>
    </v-card>
  </v-col>

【问题讨论】:

    标签: css vue.js svg css-animations vuetify.js


    【解决方案1】:

    制作动画边框有几种技术。其中之一: 你可以在你的盒子里创建四个空的 span 标签:

    <v-card>
      <span></span>
      <span></span>
      <span></span>
      <span></span>
    </v-card>
    

    它们代表边界边。它们应该绝对定位在卡片上。然后你应该提供一个关键帧无限动画来一一调整跨度的宽度。所有这些 css 逻辑都应该绑定到一个类。然后在你的 Vue 组件中根据你的计数器逻辑动态应用这个类。

    【讨论】:

      【解决方案2】:

      您可以直接使用您附加的the demo in Codepen中的SVG。

      为了在点击Reset 时重新渲染border-image,一个技巧是在SVG 字符串中添加空格,然后将其转换为base64。

      下面是一个简单的sn-p

      Vue.component('v-timer',{
        render (h) {
          return h('div', {
            style: {
              border: '10px solid black',
              borderImage: `url("data:image/svg+xml;base64,${this.computedSVGUrl}") 1`
            }
          }, [h('span', {}, `${this.inner} Secs`), h('button', {
            on: {
              click: () => {
                this.inner =  this.seconds
                this.spaces += ' '
                this.startTimer(this.seconds)
              }
            }
          }, 'Reset')])
        },
        props: {
          'seconds': {
            type: Number,
            default: 0
          }
        },
        data () {
          return {
            spaces: '',
            inner: 0,
            intervalCtrl: null
          }
        },
        computed: {
          computedSVGUrl: function () {
            return window.btoa(`<svg width='100' height='100' viewBox='0 0 100 100' fill='none' xmlns='http://www.w3.org/2000/svg'> <style>path{animation:stroke ${this.seconds}s linear;}@keyframes stroke{to{stroke-dashoffset:388;}}</style><linearGradient id='g' x1='0%' y1='0%' x2='0%' y2='100%'><stop offset='0%' stop-color='#2d3561' /><stop offset='25%' stop-color='#c05c7e' /><stop offset='50%' stop-color='#f3826f' /><stop offset='100%' stop-color='#ffb961' /></linearGradient> <path d='M1.5 1.5 l97 0l0 97l-97 0 l0 -97' stroke-linecap='square' stroke='url(#g)' stroke-width='3' stroke-dasharray='388'/> ${this.spaces} </svg>`)
          }
        },
        watch: {
          seconds: {
            handler: function (newVal) {
              this.inner = newVal
              this.startTimer(newVal)
            },
            immediate: true
          }
        },
        mounted: function () {
          this.startTimer(this.seconds)
        },
        methods: {
          startTimer: function (seconds) {
            this.resetInterval()
            this.intervalCtrl = setInterval(() => {
              this.inner -= 1
              this.inner <= 0 && this.resetInterval()
            }, 1000)
          },
          resetInterval: function () {
            this.intervalCtrl && clearInterval(this.intervalCtrl)
            this.intervalCtrl = null
          }
        }
      })
          
      new Vue ({
        el:'#app'
      })
      .timer {
        width: 200px;
        height: 30px;
      }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
      <div id="app">
          <div>
              <div>
                  <v-timer :seconds="5" class="timer"></v-timer>
                  <v-timer :seconds="10" class="timer"></v-timer>
                  <v-timer :seconds="15" class="timer"></v-timer>
              </div>
          </div>
      </div>

      【讨论】:

      • 有人能把它转换成 reactjs 吗?
      猜你喜欢
      • 2016-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-25
      • 2021-01-23
      • 2017-12-05
      相关资源
      最近更新 更多