对象模块的作用域问题

时间:2019-01-07 13:55:17

标签: javascript scope

我正在创建一个可重用的模块,该模块创建一个canvas元素并在其中绘制一个圆圈。我目前的结构是这样的。

var circle = (function () {
  return {
    init: function (el) {
      this.el = el

    },

   start: function () {

   }

  }
})()

并启动它:

for (var i = links.length - 1; i >= 0; i--) {
   circle.init(links[i])
}

我面临的问题是,我传递给模块的每个元素都将覆盖绑定到“ this”的变量。

例如。我为mouseenter添加了事件侦听器,以便在圆角中设置动画效果。 this.canvas将是最后创建的画布的值,而不是我要设置动画的画布的值。

完整代码:https://jsfiddle.net/vnLytr4q/

这个例子说明了一切。只有第一个(或循环中的最后一个)元素可以动画。

1 个答案:

答案 0 :(得分:0)

您仅创建一个circle,并在同一对象上多次调用init。您需要多次调用该函数。也称为constructor function

请参阅以下更新的代码:

var circle = function (el) {
  return {
    init: function () {
      this.el = el

      this.bounds = 0

      this.size = {
        x: 0,
        y: 0,
        radius: 0
      }

      this.angle = {
        start: -0.5,
        end: -0.5
      }

      this.start()
    },

    start: function () {
      this.addListeners()
      this.createCanvas()
      this.setBounds()
      this.draw()
    },

    addListeners: function () {
      this.el.addEventListener('mouseenter', this.onEnter.bind(this))
      this.el.addEventListener('mouseleave', this.onLeave.bind(this))

      window.addEventListener('resize', this.onResize.bind(this))
    },

    createCanvas: function () {
      this.canvas = document.createElement('canvas')
      this.el.appendChild(this.canvas)

      this.ctx = this.canvas.getContext('2d')
    },

    setBounds: function () {
      this.bounds = this.el.getBoundingClientRect()

      this.canvas.style.height = this.bounds.height + 'px'
      this.canvas.style.width = this.bounds.width + 'px'

      this.canvas.height = this.bounds.height * 2
      this.canvas.width = this.bounds.width * 2

      this.size = {
        x: this.canvas.width / 2,
        y: this.canvas.height / 2,
        radius: this.canvas.height / 2
      }
    },

    onEnter: function (e) {
      TweenMax.to(this.angle, 1, {
        end: 3.5,
        start: 1.5,
        onUpdate: this.draw.bind(this),
        ease: Power2.easeOut
      })
    },

    onLeave: function () {
      TweenMax.to(this.angle, 1, {
        end: -0.5,
        start: -0.5,
        onUpdate: this.draw.bind(this),
        ease: Power2.easeOut
      })
    },

    onResize: function () {
      this.setBounds()
      this.draw()
    },

    draw: function () {
      const { x, y, radius } = this.size
      const { start, end } = this.angle

      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)

      this.ctx.beginPath()
      this.ctx.arc(x, y, radius - 2, 0, 2 * Math.PI)
      this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.25)'
      this.ctx.lineWidth = 3
      this.ctx.stroke()

      this.ctx.beginPath()
      this.ctx.arc(x, y, radius - 2, start * Math.PI, end * Math.PI)
      this.ctx.strokeStyle = '#ffffff'
      this.ctx.lineWidth = 3
      this.ctx.stroke()
    }
  }
} // Don't execute the function here

var page = {
  init: function () {
    // get all links
    var links = document.querySelectorAll('.js-button')

    for (var i = links.length - 1; i >= 0; i--) {
      circle(links[i]).init() // Execute the function whenever you're creating a new circle
    }
  }
}

page.init()