美文网首页我爱编程
7. jQuery plugins & the stateMan

7. jQuery plugins & the stateMan

作者: _chuuuing_ | 来源:发表于2017-01-27 19:30 被阅读0次

    7.1 Introduction / 简介

    当用户试图只用Javascript处理响应式网页的时候,会发现该过程异常痛苦,因为用户必须根据屏幕大小调整代码。
    ==> 因此,Shopware推出了一个组件 StateManager,能够定义新状态,并触发callback函数(callback function)。
    另外一方面,可爱的jQuery插件并不喜欢干这些事。为了简化这个过程,Shopware导入了一个插件基类,它具有jQuery插件开发的最佳实践,并能与StateManager完美集成。

    7.2 Plugin base class / 插件基类(插件的编写)

    就像上面所提到的那样,jQuery插件基类具有jQuery插件开发的最佳实践。插件功能一览:

    • 默认配置 + 可通过自定义配置重写默认配置
    • 可通过HTML5的 data 属性配置插件
    • 支持jQuery方法链接(jQuery's method chaining)
    • 支持事件命名空间(Namespace of events)
    • 有内置函数支持删除事件监听器
    • 防止同一元素上的多重实例化
    • 检查元素是否使用某个插件的自定义表达式
    • 使用jQuery的 data -方法自动将插件绑定到元素
      由此可见,该jQuery基类为用户编写jQuery插件提供了许多有效的方法。

    7.2.1 Getting started / 基础
    以下代码展示了,如何使用插件基类编写jQuery插件的过程:

    /**
     * $.plugin(): 自动连接全局jQuery对象。
     * 该方法的两个参数:
     * para1: 插件名
     * para2: 一个对象,包含了默认配置和插件的实际实现
     */
    $.plugin('example', {
        
        /**
         * 插件的默认配置对象
         * 用户可以自定义设置。自定义后的设置会被自动整合到新对象里。该对象可通过"this.opts"在这个插件的任意方法中被访问到
         */
        defaults: {
            activeCls: 'js--is-active'
        },
        
        /**
         * "init" 方法的作用就像是插件的构造函数(constructor)
         * 可在这里对必要的元素进行缓存,并为插件注册事件监听器(Event Listener)
         * 另外,还可以现有配置的基础上修改插件的function
         */
        init: function() {
            var me = this;
            
            /**
             * 调用"applyDataAttributes" 会自动读出所有的 "data-" 属性并重写配置。
             * 如果你想要用HTML来配置你的插件,而不是通过提供一个配置对象的话,这个属性很有用。
             *
             * 比如,我们要在下面这个div元素中调用插件:
             *    <div data-activeCls="some-other-class">...</div>
             *  "data"属性会用值"some-other-class"重写 "activeCls"
             */
            me.applyDataAttributes();
            
            /**
             * 接下来,用内置函数"_on"为插件设置一个新的事件监听器(这个"_on"方法其实是在jQuery的"on"方法上添加了一些其他的特性)
             * 事件和事件监听器都会在插件特殊事件集中进行注册。该集合将自动迭代,并从元素中删除已注册的事件监听器。
             * Additionally the event name will be namespaced on the fly which
             * provides us with a safe way to remove a specific event listener from
             * an element and doesn't affect other plugins which are listening on
             * the same event.
             * (这段翻译无能。。。求助)
             */
            me._on(me.$el, 'click', function(event) {
                event.preventDefault();
                
                /**
                 * 在接下来的条件语句中,拍段元素是否在使用该插件,若在被使用,则终止
                 * 此外,这里使用 "this.$el"来初始化插件
                 */
                if(me.$el.is('plugin-example')) {
                    
                    /**
                     * 现在用变量 "this.opts" 来访问插件的配置
                     */
                    me.$el.toggleClass(me.opts.activeCls);
                }
            });
        },
        
        /**
         * "destroy" 方法可从插件外部被调用,或者在被定义的状态(state)改变时自动使用StateManager
         * 通常你需要删除那些由插件添加到元素的类,并将事件监听器也从元素上删除。
         */
        destroy: function() {
            var me = this;
        
            me.$el.removeClass(me.opts.activeCls);
            
            /**
             * 调用"_destroy"方法:移除所有用"_on"方法在基类插件上注册的事件监听器。
             * 如果想要自行迭代事件监听器,你可以使用 "this._events" 在插件中访问事件集
             */
            me._destroy();
        }
    });
    

    注意:强烈推荐jQuery插件使用基类!

    接下来,我们删去注解,看着代码解释一遍给自己听:

    $.plugin('example', {
        
        defaults: {
            activeCls: 'js--is-active'
        },
        
        init: function() {
            var me = this;
            me.applyDataAttributes();
            me._on(me.$el, 'click', function(event) {
                event.preventDefault();
                if(me.$el.is('plugin-example')) {
                    me.$el.toggleClass(me.opts.activeCls);
                }
            });
        },
        
        destroy: function() {
            var me = this;
            me.$el.removeClass(me.opts.activeCls);      
            me._destroy();
        }
    });
    

    7.2.2 Class properties / 类的属性

    • _name: String类型, 插件的名字
    • $el : jQuery类型, 将插件实例化成jQuery对象的HTML元素
    • opts : Object类型, 默认配置和用户配置的结果。==> 通过调用this.applyDataAttributes()能重写对象的属性值
    • _events : Array类型, 一个包含所有用 _on 方法注册了的事件监听器的集合

    7.2.3 Class methods / 类的方法

    • init() 模板中的方法,作用类似于插件的构造方法(the constructor of the plugin),可以用于缓存所需的HTML元素,设置事件监听等等。

    • destroy() 模板中的方法,用于删除插件。通常你会用它删除你加到某个元素上的类或者事件监听器。当你想要专门对某个特定的状态使用插件的时候,该方法很有用。

    • update() 模板中的方法,用于当状态发生改变(进入或离开一个状态)时更新插件的行为。这个方法只有在你使用了StateManager来初始化插件的时候有用。

    • _destroy() 私人方法,在插件的_events 属性中迭代已注册的事件监听器。此外,该方法可使用jQuery的removeData()方法移除插件的内存绑定(inmemory binding)。并且触发一个全局可用的观察者(observer)。

    • _on(element , event , fn) :
      element : jQuery或HTMLElement类型,特殊事件监听器的事件目标(jQuery元素 / DOM节点)
      event : String类型, 代表要监听的事件
      fn : Function类型, 当特殊类型的事件发生时,对象会收到提示(notification)
      该方法为jQuery中on()方法的代理方法,用于连接事件监听器到提供的元素, 并且在_events事件集中进行注册。

    • _off(element, event) :
      element : jQuery或HTMLElement类型,拥有事件监听器的事件目标
      event : String类型, 一个或者多个空间分离时间类型(space-separated event types),可添加可选的命名空间。或者就只是命名空间,比如 "click" 或者 "keydown.myPlugin"

    • getName() getter插件名

    • getEventName(event)
      event : String 或 Array类型,一个或多个空间分离事件类型
      将事件命名空间应用到事件类型上

    • getElement() 获取实例化插件的元素

    • getOptions() 获整合后的配置对象

    • getOption(key)
      key : String类型,配置属性的key
      自定义配置属性的getter方法

    • setOption(key, value)
      key : String类型, 配置属性的key
      value : Mixed类型, 所提供的key值
      用value值重写属性key

    • applyDataAttributes()
      获取提供的配置key,并根据元素的data属性覆盖值它

    7.3 Global jQuery event observer / 全局jQuery事件监听

    在Shopware5中添加了一个全局事件服务器(global event server),它使得用户能够在jQuery对象上定义全局事件,因此每个插件都能监听以下这些事件:

    // 注册事件
    $.publish('plugin/some-plugin/onInit', me);
    
    // 监听事件
    $.subscribe('plugin/some-plugin/onInit', function() {
        console.log('onInit');
    })
    
    // 移除事件监听器
    $.unsubscribe('plugin/some-plugin/onInit');```
    建议在注册事件监听器时,一直使用命名空间(namespace),能增加精确度,避免误删等情况。举例:
    

    $.subscribe('plugin/some-plugin/onInit.my-plugin', function() {});

    // 移除事件监听器
    $.unsubscribe('plugin/some-plugin/onInit.my-plugin');```

    7.4 The state manager / 状态管理器

    状态管理器(state manager)帮助管理不同屏幕大小时,不同的行为。实现了通过断点(breakpoint)设置不同的状态。
    断点即预定义的视窗宽度。通过输入断点范围,被注册的事件监听器的enter()函数会被调用。当到达预定义宽度之后,调用exit()函数。
    即,已注册的回调函数 在进入 / 结束预定义状态时会被调用。
    状态管理器提供了许多协助函数和填充工具,对于管理响应式设计(responsive design)十分有效。

    7.5 Use the state manager / 使用状态管理器

    在Shopware的前段javascript代码中 状态管理器是是自包含(self-containing)的全局变量。
    状态管理器的初始化:

    == 状态 XS ==
    范围:0 - 479px
    适用于:智能手机竖屏
    
    == 状态 S ==
    范围:480 - 767px
    适用于:智能手机横屏
    
    == 状态 M ==
    范围:768 - 1023px
    适用于:平板电脑竖屏
    
    == 状态 L ==
    范围:1024 - 1259px
    适用于:平板电脑横屏,笔记本电脑,台式电脑
    
    == 状态 XL ==
    范围:1260 - 5160px
    适用于:台式电脑,高分辨率的显示屏
    

    具体代码举例:

    window.StateManager.init([
            {
                state: 'xs',
                enter: 0,
                exit: 29.9375   // 479px
            },
            {
                state: 's',
                enter: 30,      // 480px
                exit: 47.9375   // 767px
            },
            {
                state: 'm',
                enter: 48,      // 768px
                exit: 63.9375   // 1023px
            },
            {
                state: 'l',
                enter: 64,      // 1024px
                exit: 78.6875   // 1259px
            },
            {
                state: 'xl',
                enter: 78.75,   // 1260px
                exit: 322.5     // 5160px
            }
        ]);
    

    注意:若默认断点与用户所要求的有出入,可以在window.StateManager.init([ ]);方法中直接修改enterexit的值

    7.5.1 Adding an event listner / 添加事件监听器
    用状态管理器注册或者移除一个事件监听器,我们通常用javascript来写。
    注册事件监听举例:

    StateManager.registerListener([{
        state: 'xs',
        enter: function() { console.log('onEnter'); },
        exit: function() { console.log('onExit'); }
    }]);
    

    事件监听器的注册支持通配符,所以enter()exit()这两个方法也可以在每个断点都被调用,具体如下:

    StateManager.registerListener([{
        state: '*',
        enter: function() { console.log('onEnter'); },
        exit: function() { console.log('onExit'); }
    }]);
    

    7.5.2 Register additional breakpoints / 注册额外的断点
    默认的断定可以通过StateManager的registerBreakpoint()方法被继承。

    注意:额外的断点不能和已存在的完全重叠

    StateManager.registerBreakpoint({
        state: 'xxl',
        enter: 78.75  // = 1260px
        exit: 90      // = 1440px
    });```
    
    **7.5.3 Class methods / 类的方法**
    `init(breakpoints)`
    `breakpoints`:Array或Object类型,最初的状态(state)
    实例化StateManager,注册预定义的断点,给html元素添加浏览器特定的类(browser specific class),设置特定设备的cookie
    
    `registerBreakpoint(breakpoints)`
    `breakpoints`:Array或Object类型,最初的状态(state)
    给State Manager注册额外断点
    
    `removeBreakpoint(state)`
    `state`:String类型,
    
    `registerListener(listener)`
    `listener`:
    
    
    `addPlugin(selector, pluginName, config, viewport)`
    `selector`:
    `pluginName`:
    `config`:
    `viewport`:
    
    `removePlugin(selector, pluginName, viewport)`
    `selector`:
    `pluginName`:
    `viewport`:
    
    `updatePlugin(selector, pluginName)`
    `selector`:
    `pluginName`:
    
    `destroyPlugin(selector, pluginName)`
    `selector`:
    `pluginName`:
    
    `getViewportWidth()`
    
    `getViewportHeight()`
    
    `getPreviousState()`
    
    `isPreviousState(state)`
    `state`:
    
    `getCurrentState()`
    
    `isCurrentState(state)`
    `state`:
    
    `isPortraitMode()`
    
    `isLandscapeMode()`
    
    `getDevicePixelRatio()`
    
    `isBrowser(browser)`
    `browser`:
    
    `getScrollBarHeight()`
    
    `matchMedia()`
    
    `requestAnimationFrame()`
    
    `cancelAnimationFrame()`
    
    `getVendorProperty(property, softError)`
    `property`:
    `softError`:
    
    ##7.6 Working with stateful jQuery plugins / jQuery插件的使用
    StateManager和jQuery插件基类的合作,简化了特定状态下(state)注册jQuery插件的过程。使组件(component)的行为根据当前state而改变。比如Offcanvas menu插件只在移动端设备(state为xs或s)上显示,在tablet和PC端被隐藏。
    state manager的作用域为前端的所有javascript代码。想要注册一个插件,只要调用state manager的`addPlugin()`方法即可。
    下面的例子中,我们将自定义的jQuery插件在状态为xs和s下进行注册。
    

    StateManager.addPlugin('.my-selector', 'myPlugin', [ 'xs', 's' ]);```

    注意:有些自定义主题的代码中没有初始化StateManager导致上面代码无效,此时需要在addPlugin之前先用init()初始化状态管理器(见7.5 Use the state manager)

    7.6.1 Passing a user configuration to the jQuery plugin / 为jQuery插件传递一个用户自定义的配置
    用户也可以将自定义的配置传递给plugin,被传递的自定义配置将与插件的默认配置进行融合(该重写的重写,没被重写的保留blablabla...)。被融合(merge)之后的配置可以通过插件中的this.opts对象取得。

    // 自定义插件配置
    $.plugin('myPlugin', {
        defaults: {
            'speed': 300
        }
    });
    
    // 注册插件
    StateManager.addPlugin('.my-selector', 'myPlugin', {
        'speed': 2000
    }, [ 'xs', 's' ]);```
    如果用户需要给插件传递一个修改过的配置,可以参照下面的模式:
    

    StateManager.addPlugin('.my-selector', 'myPlugin', {
    'speed': 300
    }).addPlugin('.my-selector', 'myPlugin', {
    'speed': 2000
    }, 's');```

    7.7 Adding javascript files to your theme / 在用户主题中添加js文件

    将js文件放在/frontend/_public目录下,然后将该路径写在Theme.php中,举例:

    /** @var array Defines the files which should be compiled by the javascript compressor */
    protected $javascript = array(
        'src/js/jquery.my-plugin.js'
    );```

    相关文章

      网友评论

        本文标题:7. jQuery plugins & the stateMan

        本文链接:https://www.haomeiwen.com/subject/szsfittx.html