【问题标题】:Resize handler works once, but not twice调整大小处理程序工作一次,但不是两次
【发布时间】:2011-01-23 02:42:11
【问题描述】:

我正在编写处理调整大小事件的代码,但遇到了一些麻烦。 代码如下:

/* 
   Timeline.js

   (Requires jquery, developed with jquery-1.4.4.min.js in mind)   
*/

/*
  Timeline's two major functions are setup and draw. After instantiating a 
  timeline object, the developer calls setup() to initialize the object. Later,
  the developer repeatedly calls on draw() to animate the canvas.
  In between, resizing the window may trigger the resize() function which 
  adjusts the timeline's dimensions and other settings.
*/
function Timeline(){
    // constants
    Timeline._BORDER_SIDES = 20; // The border on each side of the timeline,
    // We'll need this value later when calculating back's top offset
    Timeline._OFFSET_LEFT = '8px'; 
    Timeline._OFFSET_TOP = '8px'; // top border, 8px seems to be chrome default
    Timeline._BUTTON_WIDTH = 17; // The length of the back and forward buttons
    Timeline._WIDTH_FACTOR = 2/3; // How much height timeline should take up
    // variables
    Timeline._id = 0; // An id wich is unique for each instance of Timeline

    /* This function is called when the user clicks the back div*/
    this._backHandler = function(){
    alert('back clicked');
    };

    this._testResize = function(){
    alert('resized');
    };


    /*
      timeline.setup()
      Create canvas, back and forward button, as well as slider for scale.
      timeline_wrapper_id is the id of an element which is to contain this
      specific timeline.
     */    
    this.setup = function(timeline_wrapper_id){
    // add canvas
    this._id = Timeline._id++; // get id, create next id for next instance
    this._timeline_wrapper_id = timeline_wrapper_id;
    this._canvas = document.createElement('canvas');
    this._canvas.setAttribute('id', 'canvas' + this._id);
    $('#' + timeline_wrapper_id).append(this._canvas);

    // add back button
    this._back = document.createElement('div');
    this._back.setAttribute('id', 'back' + this._id); 
    // id's help us jquery stuff, ensuring their unique across instances
    // lets us potentially put several instance on the same page.

    this._back.onclick = this._backHandler; // set event handler: onclick
    $('#' + timeline_wrapper_id).append(this._back);


    this._resizeHandler = function(){
        // First, we clear all style so as to prevent duplicates
        $('#canvas' + this._id).removeAttr('style');
        $('#back' + this._id).removeAttr('style');
        // later we'll insert an empty style before modifying the style.


        // set canvas attributes

        // Width of canvas is window width, with space for borders either 
        // side.
        var canvas_width = $(window).width() - Timeline._BORDER_SIDES*2;
        var canvas_height = $(window).height() * Timeline._HEIGHT_FACTOR;


        /* The core feature of this block is the z-index. Everything else 
           is there because otherwise I can't determine the z-index. At 
           least that's what I read somewhere.

           The z-index determines how overlapping elements are drawn.
           The higher the z-index, the "closer to the user" the element is.

           In this case, we want to draw everything on top of the canvas,
           hence the lowest z-index in our application: 0.
        */
        $('#canvas'+this._id).attr('style', ''); 
        // this undoes our removeAttr('style') from earlier

        $('#canvas' + this._id).css({
        width: canvas_width,
        height: canvas_height,
        border: '1px solid', // to see what's going on
        position: 'relative', // "take canvas out of flow"-rough quote
        top: Timeline._BORDER_TOP, // seems to be the chrome default
        left: Timeline._BORDER_LEFT, // ditto
        'z-index': 0
        });

        /* Here we define the back button's visual properties. 
           Where possible, we calculate them in terms of canvas attributes,
           to achieve a consistent layout as the browser is resized.
        */
        var back_left = $('#canvas' + this._id).css('left') + 'px'; 
        // same distance from left timeline_wrapper as canvas

        // This one is a little more difficult: An explanation will follow
        // as soon as I've figured it out myself.
        var back_top = ((-1)*$('#canvas' + this._id).height() - 6) + 'px';

        $('#back' + this._id).attr('style', ''); 
        $('#back' + this._id).css({
        'background-color': '#336699',
        width: Timeline._BUTTON_WIDTH,
        height: $('#canvas' + this._id).height(), // fill canvas height
        position: 'relative', // same reason as for canvas
        left: back_left,
        top: back_top,
        'z-index': 1
        });
    };


    this._resizeHandler();
    $(window).resize(this._resizeHandler);
    };

    /*
      timeline.draw()
      Update (or set for the first time) the styles of back and forward button,
      as well as the canvas.
      Assumes setup has been called.
     */
    this.draw = function(){
    console.log('dummy');
    };
}

调用 Timeline.js 的代码非常简单:

<!doctype html>
<html>
  <head>
    <title>timeline-js</title>
    <script type="text/javascript" src="jquery-1.4.4.min.js"></script>
    <script type="text/javascript" src="Timeline.js"></script>
  </head>
  <body>
    <div id="timeline_wrapper"></div>
    <script type="text/javascript">

var timeline = new Timeline();
timeline.setup('timeline_wrapper');
// timeline.draw();
//setInterval('timeline.draw()', 60);

    </script>
  </body>
</html>

resize 函数不会在 Chrome 中抛出任何错误,并且在调用时可以这样工作:

this._resizeHandler();

错误处理程序被调用,我知道因为设置 window.onresize = this._testReszie 也可以正常工作。

但是,当我将两者结合起来时,画布不会随窗口调整大小。 有人可以在这里指出我正确的方向吗?

【问题讨论】:

标签: javascript jquery css html resize


【解决方案1】:

问题在于,在您的 _resizeHandler 函数中,this 没有引用您的 Timeline 实例。相反,它指的是window,因为这是处理程序所附加的。

修复它的方法(这不是唯一的方法)是重新定义 _resizeHandler 以便它获得对 Timeline 实例的引用。

this._resizeHandler = function(self){
  ...same code but with 'this' replaced by 'self'...
}

然后修复调用站点:

this._resizeHandler(this);
var thisTimeline = this;
$(window).resize(function() { thisTimeline._resizeHandler(thisTimeline); });
};

【讨论】:

  • 谢谢。效果很好!每个事件处理程序都会发生这种情况吗? (双关语完全承认,但不是故意的)
  • 确实如此。您只需要记住,当调用事件处理程序时,this 对象将成为事件处理程序附加到的对象。因此,您必须通过一些此类解决方法来确保您在处理程序中明确引用了您感兴趣的任何内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-29
  • 1970-01-01
  • 1970-01-01
  • 2011-12-26
  • 1970-01-01
  • 2016-05-28
相关资源
最近更新 更多