Write a BUI Fold Menu Plugin

Effect Preview

Control Analysis

Control structure

A click shows a hidden effect, and when clicked, it hides the expansion before expanding itself. Let's look at the design of the structure from the interface.

<!-- The outermost layer of a generic control is the container name of the control -->
<div class="bui-foldmenu">
    <div class="bui-foldmenu-item">menu</div>
    <div class="bui-foldmenu-content">content</div>
    <div class="bui-foldmenu-item">Menu 2</div>
    <div class="bui-foldmenu-content">Content 2</div>
</div>

Here we use a side-by-side peer approach, which is a bit cumbersome to write. In fact, this structure is consistent with dl,dt,dd, so we can optimize it to the following structure.

<!--The outermost layer of a normal control is the container name of the control-->
<dl class="bui-foldmenu">
    <dt>menu</dt>
    <dd>Content</dd>
    <dt>Menu 2</dt>
    <dd>Content 2</dd>
</dl>

The bui design is based on the button's prototype way of opening containers, which keeps each container at the same standard height, so we optimize the structure.

<!--The outermost layer of a normal control is the container name of the control-->
<dl class="bui-foldmenu">
    <dt class="bui-btn">menu</dt>
    <dd>Content</dd>
    <dt class="bui-btn">menu 2</dt>
    <dd>Content 2</dd>
</dl>

Like the effect map just now, there will be icon switching when the menu is clicked, and then combined with the layout to get the following structure, everything is laid out and everything is container.

<!-- The outermost layer of a generic control is the container name of the control -->
<dl class="bui-foldmenu">
    <dt class="bui-btn bui-box"><div class="span1">menu</div><i class="icon-foldmenu"></i></dt>
    <dd>content</dd>
    <dt class="bui-btn bui-box"><div class="span1">Menu 2</div><i class="icon-foldmenu"></i></dt>
    <dd>Content 2</dd>
</dl>

Control Style

Usually introduced as a separate style for plugins, bui-foldmenu.css file

.bui-foldmenu {}

.bui-foldmenu>dt,
.bui-foldmenu>[class*=bui-btn] {
    border: 0;
    border-bottom: 1px solid #eee;
}
/*  Default Hidden Content */
.bui-foldmenu>dd {
    display: none;
    border: 0;
    overflow-y: auto;
    border-bottom: 1px solid #eee;
    background: #fff;
}
/*  Icon */
.bui-foldmenu .icon-foldmenu {
    -webkit-transition: -webkit-transform 0.3s ease-in-out 0s;
    transition: transform 0.3s ease-in-out 0s;
}
.bui-foldmenu .icon-foldmenu:before {
    content: "\e649";
}
/* Show block on activation */
.bui-foldmenu>.active+dd {
    display: block;
}
/* Flip the arrow when activating the secondary menu */
.bui-foldmenu>.active .icon-foldmenu {
    -webkit-transform: rotate(-180deg);
    transform: rotate(-180deg);
}

Inside the style, the default hidden content label (dd adjacent to dt) is initialized by the control, and others are some modifications. When setting the active state, the arrow flips.

Control script

1.5.4 A new bui.extension method is available to extend the plug-in and remains consistent with the way bui was originally used.

The bui.extension control parameter is an object that contains the following parameters

  • name string control name
  • config object control default parameters
  • Logic of callback function control
  1. The simplest version
// The simplest version
bui.extend({
    name: "foldmenu",
    config: {
        id: ""
    },
    callback: function(opt) {

        // Public method of throwing that point to the plugin, option widget, etc.
        let that = this;
        // this.config is the result of merging with initialization parameters;
        let param = this.config;
        // Cache selector
        let $id = null;

        // Methods to throw to developers
        that.init = function(option) {
            // Merge parameters that directly call init methods
            param = $.extend(true, {}, param, option);

            // Single-page multi-page selector, if single-page, this plugin can only be used in modules, not bui.ready
            $id = bui.$(param.id);

                // Bind events, add activation styles when clicking
            $id.children("dt").click(function(e) {
                var hasActive = $(this).hasClass("active");
                if (hasActive) {
                    $(this).removeClass("active");
                } else {
                    // After adding the style, the arrows and the next level of display will be processed automatically.
                    $(this).addClass("active");
                }
            })

            return that;
        }

        // If you have a bui-dependent control, you should write it here to facilitate external calls
        // that.widgets.loading = ui.loading({
        //     appendTo: opt.id
        // });

        // If a life cycle needs to be destroyed, add it here.
        // that.beforeDestroy = function() {
        //
        //     return that;
        // }

        // id must be passed
        if (!param.id) {
            // Throw an error
            bui.showLog("Must pass id parameter.")
            return that;
        }
        // Initialize once by default
        return this.init(opt);
    }
});

Control Use

<dl id="folder" class="bui-foldmenu">
    <dt class="bui-btn">menu</dt>
    <dd>content</dd>
    <dt class="bui-btn">Menu 2</dt>
    <dd>Content 2</dd>
</dl>
  // Initialization
  var uiFloder = bui.foldmenu({id:"#folder"})

  // uiFloder.config can get some instance parameters

Plugin Preview

Online preview of bui.folder plug-in

Perfect Plugins

Use closures to prevent global pollution

Place in a closure to prevent contamination of controls. window.libs refers to zepto or jquery. When you remove the introduction of zepto.js, the introduction of jquery.js will switch to jQuery version perfectly. (jquery version is recommended at: 1.9.x - 1.11.x)

;(function(ui, $) {
    "use strict";


})(window.bui || {}, window.libs);

Add a comment

/* @namespace bui
  *  @class foldmenu
  *  @constructor
  *  @param {object} option
  * @param {string} option.id [control id]
  * @param {string} [option.handle] [clicked area]
  * @param {number} [option.height] [parent height, 0 is adaptive]
  * @param {string} [option.target] [to show hidden targets]
  * @param {number} [option.targetHeight] [Target adaptive height or restricted height]
  * @param {boolean} [option.single] [false (show multiple) | true (fold only one at a time)]
  * @param {function} [option.onInited] [Triggered after 1.5.1 new initialization]
  * @param {function} [option.callback] [callback clicking button]
  *  @example
  *
  */

Full Version

;(function(ui, $) {
    "use strict";
    /* @namespace bui
      *  @class foldmenu
      *  @constructor
      *  @param {object} option
      *  @param {string} option.id [Control id]
      *  @param {string} [option.handle] [Click Area]
      *  @param {number} [option.height] [Parent height, 0 is adaptive]
      *  @param {string} [option.target] [To show hidden targets]
      *  @param {number} [option.targetHeight] [Target Adaptive Height or Limited Height]
      *  @param {boolean} [option.single] [ false(Show Multiple) || true (fold only one at a time)]
      *  @param {function} [option.onInited] [ 1.5.1 Trigger after new initialization]
      *  @param {function} [option.callback] [ Click on the button's callback]
      *  @example
      *
      */
      ui.extend({
          name: "foldmenu",
          config: {
              id: ""
          },
          callback: function(opt) {

              // Public method of throwing that point to the plugin, option widget, etc.
              let that = this;
              // this.config is the result of merging with initialization parameters;
              let param = this.config;
              // Cache selector
              let $id = null;

              // Methods to throw to developers
              that.init = function(option) {
                  // Merge parameters that directly call init methods
                  param = $.extend(true, {}, param, option);

                  // Single-page multi-page selector, if single-page, this plugin can only be used in modules, not bui.ready
                  $id = ui.$(param.id);

                      // Bind events, add activation styles when clicking
                  $id.children("dt").click(function(e) {
                      var hasActive = $(this).hasClass("active");
                      if (hasActive) {
                          $(this).removeClass("active");
                      } else {
                          // After adding the style, the arrows and the next level of display will be processed automatically.
                          $(this).addClass("active");
                      }
                  })

                  return that;
              }

              // If you have a bui-dependent control, you should write it here to facilitate external calls
              // that.widgets.loading = ui.loading({
              //     appendTo: opt.id
              // });

              // If a life cycle needs to be destroyed, add it here.
              // that.beforeDestroy = function() {
              //
              //     return that;
              // }

              // id must be passed
              if (!param.id) {
                  // Throw an error
                  ui.showLog("Must pass id parameter.")
                  return that;
              }
              // Initialize once by default
              return this.init(opt);
          }
      });

})(window.bui || {}, window.libs);

epilogue

The above example shows the development and use of the simplest plug-in, but the adaptability of the plug-in is not enough. We also need to consider the extensibility of the plug-in, how to adapt to complex scenarios, for example, the content needs a fixed height, the selector changes to other, only one, and so on. We need to consider more scenarios.Extract more variables as configurable.

Keywords: Front-end JQuery

Added by duklaprague on Sat, 07 Sep 2019 20:17:56 +0300