`
decentway
  • 浏览: 159991 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

yui3:widget 例子_widget-extend

阅读更多

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Extending the Base Widget Class</title>

<style type="text/css">
/*margin and padding on body element
  can introduce errors in determining
  element position and are not recommended;
  we turn them off as a foundation for YUI
  CSS treatments. */
body {
	margin:0;
	padding:0;
}
</style>

<link type="text/css" rel="stylesheet" href="../../build/cssfonts/fonts-min.css" />
<script type="text/javascript" src="../../build/yui/yui-min.js"></script>


<!--begin custom header content for this example-->
<style type="text/css">
    .yui3-js-enabled .yui3-spinner-loading {
        display:none;
    }

    .yui3-spinner-hidden {
        display:none;
    }

    .yui3-spinner {
        display:-moz-inline-stack;
        display:inline-block;
        zoom:1;
        *display:inline;
        vertical-align:middle;
    }

    .yui3-spinner-content {
        padding:1px;
        position:relative;
    }

    .yui3-spinner-value {
        width:2em;
        height:1.5em;
        text-align:right;
        margin-right:22px;
        vertical-align:top;
        border:1px solid #000;
        padding:2px;
    }

    .yui3-spinner-increment, .yui3-spinner-decrement {
        position:absolute;
        height:1em;
        width:22px;
        overflow:hidden;
        text-indent:-10em;
        border:1px solid #999;
        margin:0;
        padding:0px;
    }

    .yui3-spinner-increment {
        top:1px;
        *top:2px;
        right:1px;
        background:#ddd url(assets/arrows.png) no-repeat 50% 0px;
    }

     .yui3-spinner-decrement {
        bottom:1px;
        *bottom:2px;
        right:1px;
        background:#ddd url(assets/arrows.png) no-repeat 50% -20px;
     }

    #widget-extend-example {
        padding:5px;
    }

    #widget-extend-example .hint {
        margin-top:10px;
        font-size:85%;
        color:#00a;
    }

</style>
<!--end custom header content for this example-->

</head>

<body class="yui3-skin-sam  yui-skin-sam">

<h1>Extending the Base Widget Class</h1>

<div class="exampleIntro">
	This example shows how to extend the base <code>Widget</code> class to create a simple, re-usable spinner control. The <code>Spinner</code> class created in the example is not intended to be a fully featured spinner. It is used here as a concrete example, to convey some of the key concepts to keep in mind when extending the <code>Widget</code> class.
			
</div>

<!--BEGIN SOURCE CODE FOR EXAMPLE =============================== -->
<div id="widget-extend-example">
    A basic spinner widget: <input type="text" id="numberField" class="yui3-spinner-loading" value="20" />
</div>

<script type="text/javascript">
YUI({ filter: 'raw' }).use("event-key", "widget", function(Y) {

    var Lang = Y.Lang,
        Widget = Y.Widget,
        Node = Y.Node;

    /* Spinner class constructor Spinner类构造函数 */
    function Spinner(config) {
        Spinner.superclass.constructor.apply(this, arguments);
    }

    /* 
     * Required NAME static field, to identify the Widget class and 
     * used as an event prefix, to generate class names etc. (set to the 
     * class name in camel case). 
	 *需要NAME静态属性,来标识Widget类,用来作为event前缀
	 *产生类名字(驼峰格式)
     */
    Spinner.NAME = "spinner";

    /*
     * The attribute configuration for the Spinner widget. Attributes can be
     * defined with default values, get/set functions and validator functions
     * as with any other class extending Base.
	 * 属性配置,get/set函数,validator函数
	 *
     */
    Spinner.ATTRS = {
        // The minimum value for the spinner.
        min : {
            value:0
        },

        // The maximum value for the spinner.
        max : {
            value:100
        },

        // The current value of the spinner.
        value : {
            value:0,
            validator: function(val) {
                return this._validateValue(val);
            }
        },

        // Amount to increment/decrement the spinner when the buttons or arrow up/down keys are pressed.
        minorStep : {
            value:1
        },

        // Amount to increment/decrement the spinner when the page up/down keys are pressed.
        majorStep : {
            value:10
        },

        // override default ("null"), required for focus()
        tabIndex: {
            value: 0
        },

        // The strings for the spinner UI. This attribute is 
        // defined by the base Widget class but has an empty value. The
        // spinner is simply providing a default value for the attribute.
        strings: {
            value: {
                tooltip: "这里是提示信息:Press the arrow up/down keys for minor increments, page up/down for major increments...",
                increment: "Increment",
                decrement: "Decrement"
            }
        }
    };

    /* Static constant used to identify the classname applied to the spinners value field */
	/* 静态常量被用来标识应用于spinner值域的class */
	// 产生一个类名: "yui3-spinner-button"
	//Spinner.BUTTON_TEMPLATE = Y.ClassNameManager.getClassName(Spinner.NAME, "button");
	//那么这里就产生yui3-spinner-value
    Spinner.INPUT_CLASS = Y.ClassNameManager.getClassName(Spinner.NAME, "value");

    /* Static constants used to define the markup templates used to create Spinner DOM elements */
    Spinner.INPUT_TEMPLATE = '<input type="text" class="' + Spinner.INPUT_CLASS + '">';
    Spinner.BTN_TEMPLATE = '<button type="button"></button>';

    /* 
     * The HTML_PARSER static constant is used by the Widget base class to populate 
     * the configuration for the spinner instance from markup already on the page.
     *
     * The Spinner class attempts to set the value of the spinner widget if it
     * finds the appropriate input element on the page.
     */
    Spinner.HTML_PARSER = {
        value: function (srcNode) {
            var val = parseInt(srcNode.get("value")); 
            return Y.Lang.isNumber(val) ? val : null;
        }
    };

    /* Spinner extends the base Widget class 继承base Widget类 */
    Y.extend(Spinner, Widget, {

        /*
         * initializer is part of the lifecycle introduced by 
         * the Widget class. It is invoked during construction,
         * and can be used to setup instance specific state.
         * 
         * The Spinner class does not need to perform anything
         * specific in this method, but it is left in as an example.
         */
        initializer: function() {
            // Not doing anything special during initialization
        },

        /*
         * destructor is part of the lifecycle introduced by 
         * the Widget class. It is invoked during destruction,
         * and can be used to cleanup instance specific state.
         * 
         * The spinner cleans up any node references it's holding
         * onto. The Widget classes destructor will purge the 
         * widget's bounding box of event listeners, so spinner 
         * only needs to clean up listeners it attaches outside of 
         * the bounding box.
         */
        destructor : function() {
            this._documentMouseUpHandle.detach();

            this.inputNode = null;
            this.incrementNode = null;
            this.decrementNode = null;
        },

        /*
         * renderUI is part of the lifecycle introduced by the
         * Widget class. Widget's renderer method invokes:
         *
         *     renderUI()
         *     bindUI()
         *     syncUI()
         *
         * renderUI is intended to be used by the Widget subclass
         * to create or insert new elements into the DOM. 
         *
         * For spinner the method adds the input (if it's not already 
         * present in the markup), and creates the inc/dec buttons
		 *该方法的职责是往页面中创建增加widget需要的HTML节点(或者是改变页面中现有的HTML节点)
		 *通常这是widget对DOM的第一次修改。
         */
        renderUI : function() {
            this._renderInput();
            this._renderButtons();
        },

        /*
         * bindUI is intended to be used by the Widget subclass 
         * to bind any event listeners which will drive the Widget UI.
         * 
         * It will generally bind event listeners for attribute change
         * events, to update the state of the rendered UI in response 
         * to attribute value changes, and also attach any DOM events,
         * to activate the UI.
         * 
         * For spinner, the method:
         *
         * - Sets up the attribute change listener for the "value" attribute
		 * - 设置value属性改变监听器
         *
         * - Binds key listeners for the arrow/page keys
         * - Binds mouseup/down listeners on the boundingBox, document respectively.
         * - Binds a simple change listener on the input box.
		 *该方法的职责是添加事件监听器,将UI的状态和widget的状态关联起来。
		 *这些事件监听器一般监听属性的change 事件,响应属性值的变化,改变UI的状态。
		 *该方法还负责添加DOM事件监听器,把用户交互和widget的API关联起来。
         */
        bindUI : function() {
            this.after("valueChange", this._afterValueChange);

            var boundingBox = this.get("boundingBox");
			//测试boundingBox:alert(boundingBox);

            // Looking for a key event which will fire continously across browsers while the key is held down. 38, 40 = arrow up/down, 33, 34 = page up/down
            var keyEventSpec = (!Y.UA.opera) ? "down:" : "press:";
            keyEventSpec += "38, 40, 33, 34";

            // 绑定键盘事件
			Y.on("key", Y.bind(this._onDirectionKey, this), boundingBox, keyEventSpec);
			// 绑定鼠标事件
            Y.on("mousedown", Y.bind(this._onMouseDown, this), boundingBox);
			// 设置鼠标按住上下箭头按钮时,加减数值的快慢。
            this._documentMouseUpHandle = Y.on("mouseup", Y.bind(this._onDocMouseUp, this), boundingBox.get("ownerDocument"));
			//输入节点的change事件绑定
            Y.on("change", Y.bind(this._onInputChange, this), this.inputNode);
        },

        /*
         * syncUI is intended to be used by the Widget subclass to
         * update the UI to reflect the current state of the widget.
         * 
         * For spinner, the method sets the value of the input field,
         * to match the current state of the value attribute.
		 *该方法的职责是在渲染的过程中,基于widget当前的状态设置UI的初始状态。
		 *设置一个值后,以此作为初始状态。比如滚到22,输入88,按enter,回到22
         */
        syncUI : function() {
            this._uiSetValue(this.get("value"));
        },

        /*
         * Creates the input control for the spinner and adds it to
         * the widget's content box, if not already in the markup.
		 *如果在构造函数中未提供这两个节点,widget会创建这两个节点,然后再render方法被调用的时候把这两个节点添加到页面中。如果render方法调用时,render方法的参数指向了某个节点,widget的boundingBox会被-插到这个节点中。
		 *在html里面有这样一段话:
		 *<input type="text" id="numberField" class="yui3-spinner-loading" value="20" />
		 *所以,spinner widget会以此作为boundingBox。
         */
        _renderInput : function() {
            var contentBox = this.get("contentBox"),
                input = contentBox.one("." + Spinner.INPUT_CLASS),
                strings = this.get("strings");

            if (!input) {
                input = Node.create(Spinner.INPUT_TEMPLATE);
                contentBox.appendChild(input);
            }

            input.set("title", strings.tooltip);
            this.inputNode = input;
        },

        /*
         * Creates the button controls for the spinner and add them to
         * the widget's content box, if not already in the markup.
         */
        _renderButtons : function() {
            var contentBox = this.get("contentBox"),
                strings = this.get("strings");

            var inc = this._createButton(strings.increment, this.getClassName("increment"));
            var dec = this._createButton(strings.decrement, this.getClassName("decrement"));

            this.incrementNode = contentBox.appendChild(inc);
            this.decrementNode = contentBox.appendChild(dec);
        },

        /*
         * Utility method, to create a spinner button
         */
        _createButton : function(text, className) {

            var btn = Y.Node.create(Spinner.BTN_TEMPLATE);
            btn.set("innerHTML", text);
            btn.set("title", text);
            btn.addClass(className);

            return btn;
        },

        /*
         * Bounding box mouse down handler. Will determine if the mouse down
         * is on one of the spinner buttons, and increment/decrement the value
         * accordingly.
         * 
         * The method also sets up a timer, to support the user holding the mouse
         * down on the spinner buttons. The timer is cleared when a mouse up event
         * is detected.
         */
        _onMouseDown : function(e) {
            var node = e.target,
                dir,
                handled = false,
                currVal = this.get("value"),
                minorStep = this.get("minorStep");

            if (node.hasClass(this.getClassName("increment"))) {
                this.set("value", currVal + minorStep);
                dir = 1;
                handled = true;
            } else if (node.hasClass(this.getClassName("decrement"))) {
                this.set("value", currVal - minorStep);
                dir = -1;
                handled = true;
            }

            if (handled) {
                this._setMouseDownTimers(dir, minorStep);
            }
        },

        /*
         * Override the default content box value, since we don't want the srcNode
         * to be the content box for spinner.
		 * 页面上的一个节点。在创建widget时,如果需要渐进增强地使用页面中的标签代码,开发者需要提供这个节点
         */
        _defaultCB : function() {
            return null;
        },

        /*
         * Document mouse up handler. Clears the timers supporting
         * the "mouse held down" behavior.
         */
        _onDocMouseUp : function(e) {
            this._clearMouseDownTimers();
        },

        /*
         * Bounding box Arrow up/down, Page up/down key listener.
         *
         * Increments/Decrement the spinner value, based on the key pressed.
         */
        _onDirectionKey : function(e) {

            e.preventDefault();

            var currVal = this.get("value"),
                newVal = currVal,
                minorStep = this.get("minorStep"),
                majorStep = this.get("majorStep");

            switch (e.charCode) {
                case 38:
                    newVal += minorStep;
                    break;
                case 40:
                    newVal -= minorStep;
                    break;
                case 33:
                    newVal += majorStep;
                    newVal = Math.min(newVal, this.get("max"));
                    break;
                case 34:
                    newVal -= majorStep;
                    newVal = Math.max(newVal, this.get("min"));
                    break;
            }

            if (newVal !== currVal) {
                this.set("value", newVal);
            }
        },

        /*
         * Simple change handler, to make sure user does not input an invalid value
         */
        _onInputChange : function(e) {
            if (!this._validateValue(this.inputNode.get("value"))) {
                this.syncUI();
            }
        },

        /*
         * Initiates mouse down timers, to increment slider, while mouse button
         * is held down
         */
        _setMouseDownTimers : function(dir, step) {
            this._mouseDownTimer = Y.later(500, this, function() {
                this._mousePressTimer = Y.later(100, this, function() {
                    this.set("value", this.get("value") + (dir * step));
                }, null, true)
            });
        },

        /*
         * Clears timers used to support the "mouse held down" behavior
         */
        _clearMouseDownTimers : function() {
            if (this._mouseDownTimer) {
                this._mouseDownTimer.cancel();
                this._mouseDownTimer = null;
            }
            if (this._mousePressTimer) {
                this._mousePressTimer.cancel();
                this._mousePressTimer = null;
            }
        },

        /*
         * value attribute change listener. Updates the 
         * value in the rendered input box, whenever the 
         * attribute value changes.
         */
        _afterValueChange : function(e) {
            this._uiSetValue(e.newVal);
        },

        /*
         * Updates the value of the input box to reflect 
         * the value passed in
         */
        _uiSetValue : function(val) {
            this.inputNode.set("value", val);
        },

        /*
         * value attribute default validator. Verifies that
         * the value being set lies between the min/max value
         */
        _validateValue: function(val) {
            var min = this.get("min"),
                max = this.get("max");

            return (Lang.isNumber(val) && val >= min && val <= max);
        }
    });

    // Create a new Spinner instance, drawing it's 
    // starting value from an input field already on the 
    // page (the #numberField text box)
    var spinner = new Spinner({
        srcNode: "#numberField",
        max:100,
        min:0
    });
    spinner.render();
    spinner.focus();
});
</script>

<!--END SOURCE CODE FOR EXAMPLE =============================== -->

</body>
</html>
 
分享到:
评论

相关推荐

    yuicompressor-maven-plugin

    **yuicompressor-maven-plugin详解** `yuicompressor-maven-plugin`是一款强大的Maven插件,主要用于优化前端资源,特别是JavaScript和CSS文件。这个插件是基于YUI Compressor,一个由Yahoo开发的开源工具,它能...

    webstorm_phpstorm_yuicompressor-2.4.8.jar

    标题中的"webstorm_phpstorm_yuicompressor-2.4.8.jar"正是YUI Compressor的一个版本,适用于WebStorm和PhpStorm。这个文件是Java可执行的JAR包,包含YUI Compressor的核心压缩算法,可以处理并压缩JavaScript和CSS...

    yui_js压缩min_yui_压缩工具_nan_

    "yui_js压缩min_yui_压缩工具_nan_"这个标题提到的是使用YUI Compressor这一工具,将JavaScript文件压缩成min.js格式,以达到减少文件大小、提升网页加载速度的目的。下面我们将深入探讨JavaScript压缩的必要性、YUI...

    yui-compressor 2.4.6 2011-04-15发布YUI

    yui compressor 2.4.6 发布日期:2011-04-15 用例: java -jar yuicompressor-2.4.6.jar myfile.js -o myfile-min.js

    YUI.rar_html_javascript YUI_yui_yui javascript

    3. **丰富的组件库**:YUI包含了一系列组件,如:按钮、菜单、对话框、日历、图表、拖放功能、动画效果等,满足各种网页交互需求。 4. **事件系统**:YUI的事件系统支持DOM事件的监听和处理,使开发者可以方便地响应...

    yuicompressor-yui compressor

    yuicompressor-2.4.2.jar yuicompressor-2.4.7.jar jsZip.exe yuicompressor yui compressor js压缩工具 javascript压缩工具 css压缩工具 ------------------------------------ //压缩JS java -jar yui...

    tui.code-snippet:一组便于开发 javascript 应用程序的实用方法

    TOAST UI 工具:代码片段一组实用方法,可轻松开发 javascript 应用程序。 :triangular_flag: 目录 :hammer: 用法捆 :globe_showing_Asia-Australia: 浏览器支持 :wrench: 拉取请求步骤设置发展运行... Zakas,YUI 库)

    yuicompressor-2.4.jar

    压缩JS所使用jar包!...压缩JS:java -jar yuicompressor-2.4.jar --type js xxx.js -o xxx.js --charset utf-8 压缩CSS:java -jar yuicompressor-2.4.jar --type css xxx.css -o xxx.css --charset utf-8

    yui.zip_YUI aj_ajax_ajax java_javascript_javascript YUI Ajax

    3. **slider**:这是YUI中的滑块组件,用于创建可拖动的滑动条,常用于调整设置或浏览内容。 4. **animation**:动画模块,提供了丰富的JavaScript动画效果,如淡入淡出、移动、旋转等,使网页元素动态化。 5. **...

    SlimeRefresh

    3. **ViewDragHelper**:这是Android提供的用于处理视图拖动的工具类,它可以协助实现滑动刷新的逻辑。`ViewDragHelper`可以帮助开发者监听和处理子视图的拖动事件,从而实现刷新指示器的上下移动。 4. **自定义...

    YUI.rar_compressor_js 混淆_lienae_yui

    **YUI Compressor** 是一个开源的JavaScript和CSS压缩工具,由Yahoo开发并维护,它在Web开发领域中被广泛使用。这个名为“YUI.rar_compressor_js 混淆_lienae_yui”的压缩包包含了与YUI Compressor相关的各种组件和...

    SD大会精品讲座:什么让Web2.0 Mash-up如此强大(英语授课)

    - **YUI**:提供了丰富的前端组件和工具,如表格排序、日历控件等,可以极大地提高Mashup应用的开发效率。 - **Pipes**:允许开发者通过图形界面拖拽方式来构建复杂的RSS Feed流,无需编写代码即可实现数据的抓取、...

    yuicompressor-2.4.8.jar

    yuicompressor-2.4.2.jar yuicompressor-2.4.7.jar jsZip.exe yuicompressor yui compressor js压缩工具 javascript压缩工具 css压缩工具 ------------------------------------ //压缩JS java -jar yuicompressor-...

    yui_2.9.0前端UI

    YUI 库,全称Yahoo! UI Library。是一组工具和控件,用JavaScript写成, 为的是用DOM 脚本,DHTML和AJAX等技术创建丰富的网页交互式应用程序。 YUI 基于BSD协议,对所有的使用方式都是免费的。YUI 项目包括YUI 库和两...

    Python库 | django_compressor-2.2-py2.py3-none-any.whl

    **Python库 django_compressor-2.2-py2.py3-none-any.whl** `django_compressor` 是一个用于Django框架的前端静态文件压缩库,它能够有效地优化和压缩HTML、CSS以及JavaScript资源,从而提高网页加载速度和降低...

    yui-yuidoc-yuidoc-50-529-gc631758

    【标题】"yui-yuidoc-yuidoc-50-529-gc631758" 指向的是一个关于 Yahoo User Interface Library (YUI) 和 YUIDoc 的特定版本或修订版。YUI 是一个开源的 JavaScript 库,提供了一系列模块化的工具,用于构建富有交互...

    YUICompressor.NET-3.0.0_sugar71c_Disclaimer_yuicompressor官网_yuic

    Redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met:* Redistributions of source code must retain the above ...

    yui.rar 例子

    例如,例子中可能用到了“yui-button”来创建交互式的按钮,或者使用“yui-menu”构建导航菜单,这些组件大大简化了开发工作,提升了用户体验。 在实际开发中,YUI的调试工具也非常实用。YUI Logger可以帮助开发者...

    alloy-ui:AlloyUI是一种在YUI3(JavaScript)之上构建的框架,该框架使用Bootstrap 3(HTMLCSS)提供用于构建高可扩展性应用程序的简单API

    AlloyUI ... 浏览器支持 作为用户界面框架,我们确实关心浏览器支持。... IE 8+ :check_mark: 最新的 :check_mark: 最新的 :check_mark: 最新的 :check_mark: 最新的 :check_mark: ...使用Shifter构建AlloyUI和YUI3:

Global site tag (gtag.js) - Google Analytics