Menu phải ẩn hiện hiệu ứng đẹp cho blogspot








Đầu tiên xem blog bạn có css dưới chưa nếu có rồi thì không cần chèn thêm nữa.
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
Tiếp đến các bạn chèn đoạn css dưới:
.mdui-float-left {
  float: left !important;
}
.mdui-float-right {
  float: right !important;
}

.mdui-center {
  display: block !important;
  margin-right: auto !important;
  margin-left: auto !important;
}

.mdui-valign {
  display: -webkit-box !important;
  display: -webkit-flex !important;
  display: -ms-flexbox !important;
  display:         flex !important;

  -webkit-box-align: center !important;
  -webkit-align-items: center !important;
  -ms-flex-align: center !important;
          align-items: center !important;
}

.mdui-text-left {
  text-align: left !important;
}
.mdui-text-center {
  text-align: center !important;
}
.mdui-text-right {
  text-align: right !important;
}

.mdui-text-lowercase {
  text-transform: lowercase !important;
}
.mdui-text-uppercase {
  text-transform: uppercase !important;
}
.mdui-text-capitalize {
  text-transform: capitalize !important;
}

.mdui-text-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mdui-clearfix:before,
.mdui-clearfix:after {
  display: table;
  content: " ";
}
.mdui-clearfix:after {
  clear: both;
}

.mdui-hidden,
[hidden] {
  display: none !important;
}
.mdui-invisible {
  visibility: hidden;
}

@media (max-width: 599px) {
  .mdui-hidden-xs {
    display: none !important;
  }
}
@media (min-width: 600px) and (max-width: 1023px) {
  .mdui-hidden-sm {
    display: none !important;
  }
}
@media (min-width: 1024px) and (max-width: 1439px) {
  .mdui-hidden-md {
    display: none !important;
  }
}
@media (min-width: 1440px) and (max-width: 1919px) {
  .mdui-hidden-lg {
    display: none !important;
  }
}
@media (min-width: 1920px) {
  .mdui-hidden-xl {
    display: none !important;
  }
}
@media (max-width: 599px) {
  .mdui-hidden-xs-down {
    display: none !important;
  }
}
@media (max-width: 1023px) {
  .mdui-hidden-sm-down {
    display: none !important;
  }
}
@media (max-width: 1439px) {
  .mdui-hidden-md-down {
    display: none !important;
  }
}
@media (max-width: 1919px) {
  .mdui-hidden-lg-down {
    display: none !important;
  }
}
.mdui-hidden-xl-down {
  display: none !important;
}
.mdui-hidden-xs-up {
  display: none !important;
}
@media (min-width: 600px) {
  .mdui-hidden-sm-up {
    display: none !important;
  }
}
@media (min-width: 1024px) {
  .mdui-hidden-md-up {
    display: none !important;
  }
}
@media (min-width: 1440px) {
  .mdui-hidden-lg-up {
    display: none !important;
  }
}
@media (min-width: 1920px) {
  .mdui-hidden-xl-up {
    display: none !important;
  }
}

body {
  margin: 0;
}

body {
  font-family: Roboto, Noto, Helvetica, Arial, sans-serif;
  font-size: 14px;
  color: rgba(0, 0, 0, .87);
  background-color: #fff;
}
@media (min-width: 600px) {
  body {
    font-size: 14.5px;
  }
}
@media (min-width: 1024px) {
  body {
    font-size: 15px;
  }
}
body *::-webkit-scrollbar {
  width: 8px;
  height: 8px;
  background: transparent;
}
body *::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, .2);
}
body.mdui-theme-layout-dark *::-webkit-scrollbar {
  width: 8px;
  height: 8px;
  background: transparent;
}
body.mdui-theme-layout-dark *::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .3);
}
* {
  -webkit-tap-highlight-color: transparent;
}
body.mdui-locked {
  overflow: hidden;
}
.mdui-overlay {
  position: fixed;
  top: -5000px;
  right: -5000px;
  bottom: -5000px;
  left: -5000px;
  z-index: 2000;
  visibility: hidden;
  background: rgba(0, 0, 0, .4);
  opacity: 0;
  transition-duration: .3s;
  transition-property: opacity, visibility;

  -webkit-backface-visibility: hidden;
          backface-visibility: hidden;
  will-change: opacity;
}
.mdui-overlay-show {
  visibility: visible;
  opacity: 1;
}
.mdui-no-transition {
  transition-property: none !important;
}

.mdui-icon,
.mdui-icon::before {
  /* Preferred icon size */
  display: inline-block;
  font-size: 24px;
  font-style: normal;
  font-weight: normal;
  line-height: 1;
  color: inherit;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  vertical-align: middle;

  direction: ltr;
}
.mdui-icon1,
.mdui-icon1::before {
  /* Preferred icon size */
  display: inline-block;
  font-size: 24px;
  font-style: normal;
  font-weight: normal;
  line-height: 48px;
  color: inherit;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  vertical-align: middle;

  direction: ltr;
}


.mdui-typo code {
  padding: 2px 6px;
  color: #c7254e;
  background-color: #f7f7f9;
  border-radius: 2px;
}
.mdui-typo pre code {
  padding: 0;
  font-size: inherit;
  line-height: 1.7;
  color: inherit;
  background-color: transparent;
  border-radius: 0;
}
.mdui-typo abbr[title] {
  text-decoration: none;
  cursor: help;
  border-bottom: 1px dotted;
}
.mdui-typo ins {
  text-decoration: none;
  border-bottom: 1px solid ;
}
.mdui-typo u {
  text-decoration: none;
  border-bottom: 1px solid;
}
.mdui-typo del {
  text-decoration: line-through;
}
.mdui-typo hr {
  height: 10px;
  margin-bottom: .8em;
  border: none;
  border-bottom: 1px solid rgba(0, 0, 0, .12);
}
.mdui-typo pre {
  padding: 12px 16px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid rgba(0, 0, 0, .12);
  border-radius: 2px;
}
.mdui-typo kbd {
  padding: 2px 6px;
  font-size: 90%;
  color: #fff;
  background-color: #333;
  border-radius: 2px;
}
.mdui-typo ul {
  padding-left: 2em;
  list-style: disc;
}
.mdui-typo ol {
  padding-left: 2em;
  list-style: decimal;
}
.mdui-typo li ul,
.mdui-typo li ol {
  margin: .8em 0;
}
.mdui-typo li ul {
  list-style: circle;
}
.mdui-typo img {
  max-width: 100%;
}

.mdui-headroom {
  transition: all .3s cubic-bezier(.4, 0, .2, 1) !important;
}
.mdui-headroom-pinned-top {
  -webkit-transform: translate3d(0, 0, 0) !important;
          transform: translate3d(0, 0, 0) !important;
}
.mdui-headroom-unpinned-top {
  box-shadow: none !important;
  -webkit-transform: translate3d(0, -100%, 0) !important;
          transform: translate3d(0, -100%, 0) !important;
}
.mdui-headroom-pinned-down {
  -webkit-transform: translate3d(0, 0, 0) !important;
          transform: translate3d(0, 0, 0) !important;
}
.mdui-headroom-unpinned-down {
  box-shadow: none !important;
  -webkit-transform: translate3d(0, 100%, 0) !important;
          transform: translate3d(0, 100%, 0) !important;
}
.mdui-headroom-pinned-toolbar {
  -webkit-transform: translate3d(0, 0, 0) !important;
          transform: translate3d(0, 0, 0) !important;
}
.mdui-headroom-unpinned-toolbar {
  -webkit-transform: translate3d(0, -56px, 0) !important;
          transform: translate3d(0, -56px, 0) !important;
}
@media (min-width: 600px) {
  .mdui-headroom-unpinned-toolbar {
    -webkit-transform: translate3d(0, -60px, 0) !important;
            transform: translate3d(0, -60px, 0) !important;
  }
}
@media (min-width: 1024px) {
  .mdui-headroom-unpinned-toolbar {
    -webkit-transform: translate3d(0, -64px, 0) !important;
            transform: translate3d(0, -64px, 0) !important;
  }
}
/**
 * =============================================================================
 * ************   Collapse æŠ˜å æ’ä»¶   ************
 * =============================================================================
 */
.mdui-collapse-item-header .mdui-collapse-item-arrow,
.mdui-collapse-item-header.mdui-collapse-item-arrow {
  transition: -webkit-transform .3s cubic-bezier(.4, 0, .2, 1);
  transition:         transform .3s cubic-bezier(.4, 0, .2, 1);
  transition:         transform .3s cubic-bezier(.4, 0, .2, 1), -webkit-transform .3s cubic-bezier(.4, 0, .2, 1);
  -webkit-transform: rotate(0);
          transform: rotate(0);

  will-change: transform;
}
.mdui-collapse-item-body {
  height: 0;
  padding-top: 0;
  padding-bottom: 0;
  margin-top: 0;
  margin-bottom: 0;
  overflow: hidden;
  transition: all .3s cubic-bezier(.4, 0, .2, 1);

  will-change: height;
}
.mdui-collapse-item-body .mdui-list-item {
  padding-left: 72px;
}
.mdui-collapse-item-open > .mdui-collapse-item-header .mdui-collapse-item-arrow,
.mdui-collapse-item-open > .mdui-collapse-item-header.mdui-collapse-item-arrow {
  -webkit-transform: rotate(-90deg);
          transform: rotate(-90deg);
}
.mdui-collapse-item-open > .mdui-collapse-item-body {
  height: auto;
}
/**
 * =============================================================================
 * ************   Table è¡¨æ ¼   ************
 * =============================================================================
 */
.mdui-table {
  position: relative;
  width: 100%;
  border-spacing: 0;
  border-collapse: separate;
  background-color: #fff;
  border: 1px solid rgba(0, 0, 0, .12);
  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
  /* 最后一行没有下边框 */
}
.mdui-table tbody tr {
  position: relative;
  transition: background-color .28s cubic-bezier(.4, 0, .2, 1);
}
.mdui-table th,
.mdui-table td {
  position: relative;
  box-sizing: border-box;
  padding: 12px 28px;
  text-align: left;
  vertical-align: middle;
  border-bottom: 1px solid rgba(0, 0, 0, .12);
}
.mdui-table th:last-child,
.mdui-table td:last-child {
  padding-right: 24px;
}
.mdui-table th:first-child,
.mdui-table td:first-child {
  padding-right: 0;
  padding-left: 24px;
}
.mdui-table th:nth-child(2),
.mdui-table td:nth-child(2) {
  padding-left: 24px;
}
.mdui-table tbody tr:last-child td {
  border-bottom: none;
}
.mdui-table th {
  overflow: hidden;
  font-size: 13px;
  font-weight: 700;
  line-height: 32px;
  color: rgba(0, 0, 0, .54);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mdui-table td {
  font-size: 14px;
  line-height: 24px;
  color: rgba(0, 0, 0, .87);
}
/* 每一行前面的复选框 */
.mdui-table-cell-checkbox {
  padding-top: 0 !important;
  padding-bottom: 0!important;
  padding-left: 24px !important;
}
.mdui-table-cell-checkbox .mdui-checkbox {
  margin-top: 7px;
}
.mdui-table-cell-checkbox + td,
.mdui-table-cell-checkbox + th {
  padding-left: 6px !important;
}
th.mdui-table-cell-checkbox .mdui-checkbox {
  margin-top: 11px;
}
/* é¼ æ ‡æ‚¬æµ®æ—¶è¡ŒèƒŒæ™¯åŠ æ·± */
.mdui-table-hoverable tbody tr:hover {
  background-color: #eee;
}
/* è¡¨æ ¼æ”¾åˆ°è¯¥å…ƒç´ å†…ï¼Œä½¿è¡¨æ ¼äº§ç”Ÿæ»šåŠ¨æ¡æ—¶åªåœ¨è¯¥å…ƒç´ å†…æ»šåŠ¨ */
.mdui-table-fluid {
  width: 100%;
  overflow-x: auto;
  border: 1px solid rgba(0, 0, 0, .12);
  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
}
.mdui-table-fluid .mdui-table {
  margin: 0;
  border: none;
  box-shadow: none;
}
/* 数字列,右对齐 */
.mdui-table-col-numeric {
  text-align: right !important;
}
/* 行处于选中状态 */
.mdui-table-row-selected {
  background-color: #f5f5f5;
}
/**
 * =============================================================================
 * ************   Table dark   ************
 * =============================================================================
 */
.mdui-theme-layout-dark .mdui-table {
  background-color: #303030;
  border: 1px solid rgba(255, 255, 255, .12);
}
.mdui-theme-layout-dark .mdui-table th,
.mdui-theme-layout-dark .mdui-table td {
  border-bottom: 1px solid rgba(255, 255, 255, .12);
}
.mdui-theme-layout-dark .mdui-table th {
  color: rgba(255, 255, 255, .7);
}
.mdui-theme-layout-dark .mdui-table td {
  color: #fff;
}
.mdui-theme-layout-dark .mdui-table-hoverable tbody tr:hover {
  background-color: #616161;
}
.mdui-theme-layout-dark .mdui-table-fluid {
  border: 1px solid rgba(255, 255, 255, .12);
}
.mdui-theme-layout-dark .mdui-table-fluid .mdui-table {
  border: none;
  box-shadow: none;
}
.mdui-theme-layout-dark .mdui-table-row-selected {
  background-color: #424242;
}
/**
 * =============================================================================
 * ************   Divider 分割线   ************
 * =============================================================================
 */
.mdui-divider,
.mdui-divider-light,
.mdui-divider-dark,
.mdui-divider-inset,
.mdui-divider-inset-light,
.mdui-divider-inset-dark {
  height: 1px;
  margin: -1px 0 0 0;
  border: none;
}
.mdui-divider-inset,
.mdui-divider-inset-light,
.mdui-divider-inset-dark {
  margin-left: 72px;
}
.mdui-divider,
.mdui-divider-inset {
  background-color: rgba(0, 0, 0, .12);
}
.mdui-theme-layout-dark .mdui-divider,
.mdui-theme-layout-dark .mdui-divider-inset {
  background-color: rgba(255, 255, 255, .12);
}
.mdui-divider-light,
.mdui-divider-inset-light {
  background-color: rgba(255, 255, 255, .12);
}
.mdui-divider-dark,
.mdui-divider-inset-dark {
  background-color: rgba(0, 0, 0, .12);
}

.mdui-img-fluid,
.mdui-video-fluid {
  display: block;
  max-width: 100%;
  height: auto;
}
/* 圆角图片 */
.mdui-img-rounded {
  border-radius: 2px;
}
/* 圆形图片 */
.mdui-img-circle {
  border-radius: 50%;
}
.mdui-video-container {
  position: relative;
  height: 0;
  padding-bottom: 56.25%;
  overflow: hidden;
}
.mdui-video-container iframe,
.mdui-video-container object,
.mdui-video-container embed {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.mdui-ripple {
  position: relative;
  overflow: hidden;
  cursor: pointer;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}
/* Ripple */
.mdui-ripple-wave {
  position: absolute !important;
  top: 0;
  left: 0;
  z-index: 1;
  padding: 0;
  margin: 0;
  font-size: 0;
  pointer-events: none;
  background-color: rgba(0, 0, 0, .1);
  border-radius: 50%;
  transition-duration: 1400ms;
  -webkit-transform: translate3d(0px, 0px, 0) scale(0);
          transform: translate3d(0px, 0px, 0) scale(0);
}
/* 有背景色的默认使用白色涟漪 */
.mdui-ripple[class*="mdui-color-"] .mdui-ripple-wave {
  background-color: rgba(255, 255, 255, .3);
}
/* 白色涟漪 */
.mdui-ripple-white .mdui-ripple-wave {
  background-color: rgba(255, 255, 255, .3) !important;
}
/* 黑色涟漪 */
.mdui-ripple-black .mdui-ripple-wave {
  background-color: rgba(0, 0, 0, .1) !important;
}
.mdui-ripple-wave-fill {
  opacity: .35;
  transition-duration: 300ms;
}
.mdui-ripple-wave-out {
  opacity: 0;
  transition-duration: 600ms;
}

.mdui-btn,
.mdui-fab {
  position: relative;
  display: inline-block;
  min-width: 88px;
  height: 36px;
  box-sizing: border-box;
  padding: 0 16px;
  margin: 0;
  overflow: hidden;
  font-size: 14px;
  font-weight: 500;
  line-height: 36px;
  color: inherit;
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: .04em;
  white-space: nowrap;
  vertical-align: middle;
  -ms-touch-action: manipulation;
      touch-action: manipulation;
  cursor: pointer;
  zoom: 1;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  background: transparent;
  border: none;
  border-radius: 2px;
  outline: none;
  transition: all .2s cubic-bezier(.4, 0, .2, 1), box-shadow .2s cubic-bezier(.4, 0, 1, 1);

  will-change: box-shadow;
  -webkit-user-drag: none;
}
.mdui-btn::-moz-focus-inner,
.mdui-fab::-moz-focus-inner {
  border: 0;
}
.mdui-btn:hover,
.mdui-fab:hover {
  background-color: rgba(0, 0, 0, .1);
}
.mdui-btn:not(.mdui-ripple):active,
.mdui-fab:not(.mdui-ripple):active {
  background-color: rgba(0, 0, 0, .165);
}
.mdui-btn[class*="mdui-color-"]:hover,
.mdui-fab[class*="mdui-color-"]:hover {
  opacity: .87;
}
.mdui-btn:not(.mdui-ripple)[class*="mdui-color-"]:active,
.mdui-fab:not(.mdui-ripple)[class*="mdui-color-"]:active {
  opacity: .76;
}
/* æŒ‰é’®å†…çš„å›¾æ ‡ */
.mdui-btn .mdui-icon-left,
.mdui-btn .mdui-icon-right,
.mdui-btn .mdui-icon-left::before,
.mdui-btn .mdui-icon-right::before {
  height: inherit;
  font-size: 1.3em;
  line-height: inherit;
}
.mdui-btn .mdui-icon-left {
  float: left;
  margin-right: .4em;
}
.mdui-btn .mdui-icon-right {
  float: right;
  margin-left: .4em;
}
input.mdui-btn[type="submit"] {
  -webkit-appearance: none;
}
/* Raised button 浮动按钮 */
.mdui-btn-raised {
  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
}
.mdui-btn-raised:hover {
  box-shadow: 0 2px 4px -1px rgba(0, 0, 0, .2), 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12);
}
.mdui-btn-raised:active {
  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12);
}
/* 禁用按钮 */
.mdui-btn[disabled],
.mdui-fab[disabled],
.mdui-btn[disabled]:hover,
.mdui-fab[disabled]:hover,
.mdui-btn[disabled]:active,
.mdui-fab[disabled]:active,
.mdui-btn[disabled]:focus,
.mdui-fab[disabled]:focus {
  color: rgba(0, 0, 0, .26) !important;
  cursor: default !important;
  background-color: transparent !important;
  box-shadow: none !important;
}
.mdui-btn[disabled] .mdui-icon,
.mdui-fab[disabled] .mdui-icon,
.mdui-btn[disabled]:hover .mdui-icon,
.mdui-fab[disabled]:hover .mdui-icon,
.mdui-btn[disabled]:active .mdui-icon,
.mdui-fab[disabled]:active .mdui-icon,
.mdui-btn[disabled]:focus .mdui-icon,
.mdui-fab[disabled]:focus .mdui-icon {
  color: rgba(0, 0, 0, .26) !important;
}
/* 禁用状态浮动按钮和浮动操作按钮 */
.mdui-btn-raised[disabled],
.mdui-fab[disabled],
.mdui-btn-raised[disabled]:hover,
.mdui-fab[disabled]:hover,
.mdui-btn-raised[disabled]:active,
.mdui-fab[disabled]:active,
.mdui-btn-raised[disabled]:focus,
.mdui-fab[disabled]:focus {
  background-color: rgba(0, 0, 0, .12) !important;
  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12) !important;
}
/* åŠ ç²—æŒ‰é’®æ–‡æœ¬ */
.mdui-btn-bold {
  font-weight: bold;
}
/* å›¾æ ‡æŒ‰é’® */
.mdui-btn-icon {
  width: 36px;
  min-width: 36px;
  height: 36px;
  padding: 0;
  margin-right: 0;
  margin-left: 0;
  overflow: hidden;
  font-size: 24px;
  line-height: normal;
  border-radius: 50%;
}
.mdui-btn-icon .mdui-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 24px;
  line-height: 24px;
  -webkit-transform: translate(-12px, -12px);
          transform: translate(-12px, -12px);
}
.mdui-btn-icon.mdui-ripple {
  -webkit-transform: translateZ(0);
          transform: translateZ(0);
}
/* 按钮 100% 宽度 */
.mdui-btn-block {
  display: block;
  width: 100%;
}
/* 密集型按钮 */
.mdui-btn-dense {
  height: 32px;
  font-size: 13px;
  line-height: 32px;
}
.mdui-btn-dense.mdui-btn-icon {
  width: 32px;
  min-width: 32px;
}

.mdui-list {
  padding: 8px 0;
  margin: 0;
  list-style: none;
  background-color: transparent;
}
.mdui-list .mdui-list {
  padding: 0;
}
.mdui-list > .mdui-divider,
.mdui-list > .mdui-divider-light,
.mdui-list > .mdui-divider-dark,
.mdui-list > .mdui-divider-inset,
.mdui-list > .mdui-divider-inset-light,
.mdui-list > .mdui-divider-inset-dark {
  margin-top: 8px;
  margin-bottom: 8px;
}
.mdui-list a {
  color: inherit;
  text-decoration: none;
}
.mdui-list .mdui-subheader,
.mdui-list .mdui-subheader-inset {
  margin-top: 8px;
}
.mdui-list .mdui-subheader:before,
.mdui-list .mdui-subheader-inset:before {
  position: absolute;
  right: 0;
  left: 0;
  display: block;
  height: 1px;
  content: ' ';
  background-color: rgba(0, 0, 0, .12);
}
.mdui-list .mdui-subheader:first-child,
.mdui-list .mdui-subheader-inset:first-child {
  margin-top: -8px;
}
.mdui-list .mdui-subheader:first-child:before,
.mdui-list .mdui-subheader-inset:first-child:before {
  background-color: transparent;
}
.mdui-list .mdui-subheader-inset:before {
  left: 72px;
}
/* 列表项 */
.mdui-list-item {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display:         flex;
  min-height: 48px;
  box-sizing: border-box;
  padding: 0;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .3s cubic-bezier(.4, 0, .2, 1);

  -webkit-box-align: center;
  -webkit-align-items: center;
  -ms-flex-align: center;
          align-items: center;
}
.mdui-list-item:hover {
  background-color: rgba(0, 0, 0, .08);
}
.mdui-list-item:after {
  height: 48px;
  visibility: hidden;
  content: ' ';
}
/* åˆ—è¡¨é¡¹å›¾æ ‡ */
.mdui-list-item-icon {
  width: 24px;
  min-width: 24px;
  height: 24px;
  color: rgba(0, 0, 0, .54);
}
/* 列表项头像 */
.mdui-list-item-avatar {
  min-width: 40px;
  max-width: 40px;
  height: 40px;
  margin-top: 8px;
  margin-bottom: 8px;
  line-height: 40px;
  color: #fff;
  text-align: center;
  background-color: #bdbdbd;
  border-radius: 50%;
}
.mdui-list-item-avatar img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
}
/* 列表项内容 */
.mdui-list-item-content {
  padding-top: 14px;
  padding-bottom: 14px;
  font-size: 16px;
  font-weight: 400;
  line-height: 20px;

  -webkit-box-flex: 1;
  -webkit-flex-grow: 1;
  -ms-flex-positive: 1;
          flex-grow: 1;
}
/* 列表项内容的副内容 */
.mdui-list-item-text {
  font-size: 14px;
  color: rgba(0, 0, 0, .54);
}
.mdui-list-item-title ~ .mdui-list-item-text {
  margin-top: 4px;
}
/* 激活状态的列表项 */
.mdui-list-item-active {
  font-weight: 700;
  background-color: rgba(0, 0, 0, .08);
}
.mdui-list-item-active .mdui-list-item-content {
  font-weight: 700;
}
.mdui-list-item-active .mdui-list-item-text {
  font-weight: 400;
}
/* 限制文本高度 */
.mdui-list-item-one-line,
.mdui-list-item-two-line,
.mdui-list-item-three-line {
  display: -webkit-box;
  overflow: hidden;
  text-overflow: ellipsis;

  -webkit-box-orient: vertical;
}
.mdui-list-item-one-line {
  height: 20px;

  -webkit-line-clamp: 1;
}
.mdui-list-item-two-line {
  height: 40px;

  -webkit-line-clamp: 2;
}
.mdui-list-item-three-line {
  height: 60px;

  -webkit-line-clamp: 3;
}
/* åˆ—è¡¨é¡¹å†…çš„å…ƒç´ é—´æ·»åŠ é—´è· */
.mdui-list-item-icon ~ .mdui-list-item-content {
  margin-left: 32px;
}
.mdui-checkbox ~ .mdui-list-item-content,
.mdui-radio ~ .mdui-list-item-content,
.mdui-switch ~ .mdui-list-item-content {
  margin-left: 20px;
}
.mdui-list-item-avatar ~ .mdui-list-item-content {
  margin-left: 16px;
}
.mdui-list-item-content ~ .mdui-list-item-icon,
.mdui-list-item-content ~ .mdui-list-item-avatar,
.mdui-list-item-content ~ .mdui-checkbox,
.mdui-list-item-content ~ .mdui-radio,
.mdui-list-item-content ~ .mdui-switch {
  margin-left: 16px;
}
.mdui-list-item-content ~ .mdui-checkbox,
.mdui-list-item-content ~ .mdui-radio {
  padding-left: 24px;
}
/* 密集型列表 */
.mdui-list-dense {
  padding: 4px 0;
  font-size: 13px;
}
.mdui-list-dense > .mdui-divider,
.mdui-list-dense > .mdui-divider-light,
.mdui-list-dense > .mdui-divider-dark,
.mdui-list-dense > .mdui-divider-inset,
.mdui-list-dense > .mdui-divider-inset-light,
.mdui-list-dense > .mdui-divider-inset-dark {
  margin-top: 4px;
  margin-bottom: 4px;
}
.mdui-list-dense .mdui-subheader,
.mdui-list-dense .mdui-subheader-inset {
  height: 40px;
  margin-top: 4px;
  line-height: 40px;
}
.mdui-list-dense .mdui-subheader:first-child,
.mdui-list-dense .mdui-subheader-inset:first-child {
  margin-top: -4px;
}
.mdui-list-dense .mdui-list-item {
  min-height: 40px;
}
.mdui-list-dense .mdui-list-item:after {
  height: 40px;
}
.mdui-list-dense .mdui-list-item-icon {
  width: 20px;
  height: 20px;
  font-size: 20px;
}
.mdui-list-dense .mdui-list-item-avatar {
  min-width: 36px;
  height: 36px;
  min-height: 36px;
}
.mdui-list-dense .mdui-list-item-content {
  padding-top: 11px;
  padding-bottom: 11px;
  font-size: 13px;
  line-height: 18px;
}
.mdui-list-dense .mdui-list-item-text {
  font-size: 13px;
}
.mdui-list-dense .mdui-list-item-title ~ .mdui-list-item-text {
  margin-top: 2px;
}
.mdui-list-dense .mdui-list-item-one-line {
  height: 18px;
}
.mdui-list-dense .mdui-list-item-two-line {
  height: 36px;
}
.mdui-list-dense .mdui-list-item-three-line {
  height: 54px;
}


body.mdui-loaded {
  transition: padding .3s cubic-bezier(0, 0, .2, 1);
}
body.mdui-loaded .mdui-drawer {
  transition: all .3s cubic-bezier(0, 0, .2, 1);
}
.mdui-drawer {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 5000;
  width: 240px;
  box-sizing: border-box;
  margin: 0;
  overflow-x: hidden;
  overflow-y: auto;
  white-space: nowrap;

  will-change: transform;
}
/* å‡ºçŽ°åœ¨å³ä¾§çš„æŠ½å±‰æ  */
.mdui-drawer-right {
  right: 0;
  left: auto;
}
/* æ‰‹æœºå¹³æ¿ä¸Šçš„æ ·å¼ */
@media (max-width: 1023px) {
  .mdui-drawer {
    /* 始终有背景和阴影 */
    background-color: #fff;
    box-shadow: 0 8px 10px -5px rgba(0, 0, 0, .2), 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12);
    /* 默认隐藏 */
    -webkit-transform: translateX(-250px);
            transform: translateX(-250px);
  }
  .mdui-drawer-right {
    /* 右侧 drawer 也默认隐藏 */
    -webkit-transform: translateX(250px);
            transform: translateX(250px);
  }
}
/* å¼ºåˆ¶éšè—æŠ½å±‰æ  */
.mdui-drawer-close {
  -webkit-transform: translateX(-250px);
          transform: translateX(-250px);
          box-shadow: none;
}
.mdui-drawer-close.mdui-drawer-right {
  -webkit-transform: translateX(250px);
          transform: translateX(250px);
}
/* å¼ºåˆ¶æ˜¾ç¤ºæŠ½å±‰æ  */
.mdui-drawer-open {
  -webkit-transform: translateX(0) !important;
          transform: translateX(0) !important;
}
/* PC ä¸Šçš„æ ·å¼ */
@media (min-width: 1024px) {
  /* 使 body 获得 padding-left 或 padding-rightï¼Œé¿å…è¢«æŠ½å±‰æ è¦†ç›–ä½é¡µé¢ */
  body.mdui-drawer-body-left {
    padding-left: 240px;
  }
  body.mdui-drawer-body-right {
    padding-right: 240px;
  }
  /* PC 上默认有上边距 */
  .mdui-appbar-with-toolbar .mdui-drawer {
    top: 64px;
  }
  .mdui-appbar-with-tab .mdui-drawer {
    top: 48px;
  }
  .mdui-appbar-with-tab-larger .mdui-drawer {
    top: 72px;
  }
  .mdui-appbar-with-toolbar.mdui-appbar-with-tab .mdui-drawer {
    top: 112px;
  }
  .mdui-appbar-with-toolbar.mdui-appbar-with-tab-larger .mdui-drawer {
    top: 136px;
  }
}



.mdui-progress {
  position: relative;
  display: block;
  width: 100%;
  height: 4px;
  overflow: hidden;
  background-color: rgba(63, 81, 181, .2);
  border-radius: 2px;
}
/* 确定进度的线性进度条 */
.mdui-progress-determinate {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  background-color: #3f51b5;
  transition: width .3s linear;
}
/* 不确定进度的线性进度条 */
.mdui-progress-indeterminate {
  background-color: #3f51b5;
}
.mdui-progress-indeterminate:before {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  content: ' ';
  background-color: inherit;
  -webkit-animation: mdui-progress-indeterminate 2s linear infinite;
          animation: mdui-progress-indeterminate 2s linear infinite;

  will-change: left, width;
}
.mdui-progress-indeterminate:after {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  content: ' ';
  background-color: inherit;
  -webkit-animation: mdui-progress-indeterminate-short 2s linear infinite;
          animation: mdui-progress-indeterminate-short 2s linear infinite;

  will-change: left, width;
}
@-webkit-keyframes mdui-progress-indeterminate {
  0% {
    left: 0;
    width: 0;
  }
  50% {
    left: 30%;
    width: 70%;
  }
  75% {
    left: 100%;
    width: 0;
  }
}
@keyframes mdui-progress-indeterminate {
  0% {
    left: 0;
    width: 0;
  }
  50% {
    left: 30%;
    width: 70%;
  }
  75% {
    left: 100%;
    width: 0;
  }
}
@-webkit-keyframes mdui-progress-indeterminate-short {
  0% {
    left: 0;
    width: 0;
  }
  50% {
    left: 0;
    width: 0;
  }
  75% {
    left: 0;
    width: 25%;
  }
  100% {
    left: 100%;
    width: 0;
  }
}
@keyframes mdui-progress-indeterminate-short {
  0% {
    left: 0;
    width: 0;
  }
  50% {
    left: 0;
    width: 0;
  }
  75% {
    left: 0;
    width: 25%;
  }
  100% {
    left: 100%;
    width: 0;
  }
}

header{
 height:48px;
 line-height: 48px;
 text-align: center;
 font-size:1.5em;
    background-color: #00b355;
    color:#fff;
}

/*列表页*/
.backprev{
 float:left;
 width: 15%;
    text-align: center;
    color: #fff;
    height: 48px;
    line-height: 48px;
}
.head-middle{
    width: 70%;
    text-align: center;
    float: left;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.head-right{
 float:right;
 text-align: center;
 width:15%;
}
.app-hide-list i{
    margin-top: -3px;
    margin-right: 5px;
}
.app-hide-list{
    background: #f5f5f5;
    margin:5px 0;
    color:#007d3c;
}
.app-slide-menu .mdui-list-item-content{
    text-align: left;
    padding-left: .8em;
}
.app-collapse-menu{
    margin:0 16px;
}
.app-list-home{
    padding:0;
    margin:5px 0 10px;
    background: #00b355;
}
.app-list-home:hover{
    background: #00b355;
}
.app-list-home i{
    margin-top: -3px;
    margin-right: 5px;
    color:#fff;
}
.app-list-home a{
    color:#fff;
}
.app-list-item-link{
    color:#fff;
    display: block;
    width:100%;
    text-align: left;
}
.mdui-collapse-item-body .app-sub-list{
    padding:0 ;
    margin: 8px;
    background: #fff;
}
.mdui-collapse-item-body .app-sub-list a{
    padding-left:23px;
}
.app-collapse-list{
    margin:10px 0;
}
.menu-click{
    background: #e1fff0;
}
.app-btn{
 min-width: 100%;
 text-align: center;
 padding:0;
}


Đoạn code hiện thị menu dưới đây:

<header>
 <a class="backprev" href="javascript:history.back(-1);">
  <i class="mdui-icon1 fa fa-long-arrow-left"></i>
 </a>
 <div class="head-middle">CHIA SẺ 78</div>
 <div class="head-right">
  <button class="mdui-btn app-btn" mdui-drawer="{target: '#left-drawer'}"><i class="mdui-icon1 material-icons fa fa-ellipsis-h"></i></button>
  <div class="mdui-drawer mdui-drawer-right mdui-drawer-close" id="left-drawer">

   <ul class="mdui-list app-slide-menu app-collapse-menu" mdui-collapse="{accordion: true}">
      <li class="mdui-list-item mdui-ripple app-list-home ">
       <a href="#" class="app-list-item-link mdui-text-left ">
        <div class="mdui-list-item-content">
       <i class="mdui-list-item-icon mdui-icon material-icons fa fa-home">
         </i>Trang Chủ
        </div>
       </a>
      </li>
    <li class="mdui-collapse-item  app-hide-list  app-collapse-list">
     <div class="mdui-collapse-item-header mdui-list-item mdui-ripple  mdui-p-x-0">
      <div class="menu-click mdui-list-item-content mdui-text-left" onclick="">
       Colum 1
       <i class="mdui-collapse-item-arrow mdui-icon material-icons fa fa-angle-right mdui-float-right">
       </i>
      </div>
     </div>
     <ul class="mdui-collapse-item-body mdui-list mdui-list-dense">
      <li class="mdui-list-item mdui-ripple app-sub-list  app-hide-list">
       <a href="#" class="app-list-item-link mdui-text-left">
        Secondary section
       </a>
      </li>
      <li class="mdui-list-item mdui-ripple app-sub-list  app-hide-list">
       <a href="#" class="app-list-item-link mdui-text-left">
        Secondary section
       </a>
      </li>
     </ul>
    </li>
    <li class="mdui-collapse-item  app-hide-list  app-collapse-list">
     <div class="mdui-collapse-item-header mdui-list-item mdui-ripple  mdui-p-x-0">
      <div class="menu-click mdui-list-item-content mdui-text-left" onclick="">
       Colum 2
       <i class="mdui-collapse-item-arrow mdui-icon material-icons fa fa-angle-right mdui-float-right">
       </i>
      </div>
     </div>
     <ul class="mdui-collapse-item-body mdui-list mdui-list-dense">
      <li class="mdui-list-item mdui-ripple app-sub-list  app-hide-list">
       <a href="#" class="app-list-item-link mdui-text-left">
        Secondary section
       </a>
      </li>
      <li class="mdui-list-item mdui-ripple app-sub-list  app-hide-list">
       <a href="#" class="app-list-item-link mdui-text-left">
        Secondary section
       </a>
      </li>
      <li class="mdui-list-item mdui-ripple app-sub-list  app-hide-list">
       <a href="#" class="app-list-item-link mdui-text-left">
        Secondary section
       </a>
      </li>
      <li class="mdui-list-item mdui-ripple app-sub-list  app-hide-list">
       <a href="#" class="app-list-item-link mdui-text-left">
        Secondary section
       </a>
      </li>
     </ul>
    </li>
    <li class="mdui-collapse-item app-hide-list  app-collapse-list">
       <a href="#" class=" mdui-list-item mdui-ripple  mdui-p-x-0">
      <div class="menu-click mdui-list-item-content mdui-text-left">
       Colum 3
       <i class="mdui-collapse-item-arrow mdui-icon material-icons fa fa-angle-right mdui-float-right">
       </i>
      </div>
     </a>
    </li>
   </ul>
  </div>
 </div>
</header>

Cuối cùng là đoạn JS nữa là xong:
<script>

;(function (window, document, undefined) {
  'use strict';

  var mdui = {};

  (function () {
    var lastTime = 0;

    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = window.webkitRequestAnimationFrame;
      window.cancelAnimationFrame = window.webkitCancelAnimationFrame;
    }

    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = function (callback, element) {
        var currTime = new Date().getTime();
        var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));

        var id = window.setTimeout(function () {
            callback(currTime + timeToCall);
          }, timeToCall);

        lastTime = currTime + timeToCall;
        return id;
      };
    }

    if (!window.cancelAnimationFrame) {
      window.cancelAnimationFrame = function (id) {
        clearTimeout(id);
      };
    }
  })();


 
  var $ = (function (window, document, undefined) {
    'use strict';


    var emptyArray = [];
    var slice = emptyArray.slice;
    var concat = emptyArray.concat;
    var isArray = Array.isArray;

    var documentElement = document.documentElement;


    function isArrayLike(obj) {
      return typeof obj.length === 'number';
    }


    function each(obj, callback) {
      var i;
      var prop;

      if (isArrayLike(obj)) {
        for (i = 0; i < obj.length; i++) {
          if (callback.call(obj[i], i, obj[i]) === false) {
            return obj;
          }
        }
      } else {
        for (prop in obj) {
          if (obj.hasOwnProperty(prop)) {
            if (callback.call(obj[prop], prop, obj[prop]) === false) {
              return obj;
            }
          }
        }
      }

      return obj;
    }

    function map(elems, callback) {
      var value;
      var ret = [];

      each(elems, function (i, elem) {
        value = callback(elem, i);
        if (value !== null && value !== undefined) {
          ret.push(value);
        }
      });

      return concat.apply([], ret);
    }

    /**
     * 把对象合并到第一个参数中,并返回第一个参数
     * @param first
     * @param second
     * @returns {*}
     */
    function merge(first, second) {
      each(second, function (i, val) {
        first.push(val);
      });

      return first;
    }

    /**
     * 返回去重后的数组
     * @param arr
     * @returns {Array}
     */
    function unique(arr) {
      var unique = [];
      for (var i = 0; i < arr.length; i++) {
        if (unique.indexOf(arr[i]) === -1) {
          unique.push(arr[i]);
        }
      }

      return unique;
    }

    /**
     * 是否是 null
     * @param obj
     * @returns {boolean}
     */
    function isNull(obj) {
      return obj === null;
    }

    /**
     * 判断一个节点名
     * @param ele
     * @param name
     * @returns {boolean}
     */
    function nodeName(ele, name) {
      return ele.nodeName && ele.nodeName.toLowerCase() === name.toLowerCase();
    }

    function isFunction(fn) {
      return typeof fn === 'function';
    }

    function isString(obj) {
      return typeof obj === 'string';
    }

    function isObject(obj) {
      return typeof obj === 'object';
    }

    /**
     * 除去 null 后的 object 类型
     * @param obj
     * @returns {*|boolean}
     */
    function isObjectLike(obj) {
      return isObject(obj) && !isNull(obj);
    }

    function isWindow(win) {
      return win && win === win.window;
    }

    function isDocument(doc) {
      return doc && doc.nodeType === doc.DOCUMENT_NODE;
    }

    var elementDisplay = {};

    /**
     * èŽ·å–å…ƒç´ çš„é»˜è®¤ display æ ·å¼å€¼ï¼Œç”¨äºŽ .show() 方法
     * @param nodeName
     * @returns {*}
     */
    function defaultDisplay(nodeName) {
      var element;
      var display;

      if (!elementDisplay[nodeName]) {
        element = document.createElement(nodeName);
        document.body.appendChild(element);
        display = getComputedStyle(element, '').getPropertyValue('display');
        element.parentNode.removeChild(element);
        if (display === 'none') {
          display = 'block';
        }

        elementDisplay[nodeName] = display;
      }

      return elementDisplay[nodeName];
    }


    var JQ = function (arr) {
      var _this = this;

      for (var i = 0; i < arr.length; i++) {
        _this[i] = arr[i];
      }

      _this.length = arr.length;

      return this;
    };

    /**
     * @param selector {String|Function|Node|Window|NodeList|Array|JQ=}
     * @returns {JQ}
     */
    var $ = function (selector) {
      var arr = [];
      var i = 0;

      if (!selector) {
        return new JQ(arr);
      }

      if (selector instanceof JQ) {
        return selector;
      }

      if (isString(selector)) {
        var els;
        var tempParent;
        selector = selector.trim();

        // 创建 HTML 字符串
        if (selector[0] === '<' && selector[selector.length - 1] === '>') {
          // HTML
          var toCreate = 'div';
          if (selector.indexOf('<li') === 0) {
            toCreate = 'ul';
          }

          if (selector.indexOf('<tr') === 0) {
            toCreate = 'tbody';
          }

          if (selector.indexOf('<td') === 0 || selector.indexOf('<th') === 0) {
            toCreate = 'tr';
          }

          if (selector.indexOf('<tbody') === 0) {
            toCreate = 'table';
          }

          if (selector.indexOf('<option') === 0) {
            toCreate = 'select';
          }

          tempParent = document.createElement(toCreate);
          tempParent.innerHTML = selector;
          for (i = 0; i < tempParent.childNodes.length; i++) {
            arr.push(tempParent.childNodes[i]);
          }
        }

        // 选择器
        else {

          // id 选择器
          if (selector[0] === '#' && !selector.match(/[ .<>:~]/)) {
            els = [document.getElementById(selector.slice(1))];
          }

          // 其他选择器
          else {
            els = document.querySelectorAll(selector);
          }

          for (i = 0; i < els.length; i++) {
            if (els[i]) {
              arr.push(els[i]);
            }
          }
        }
      }

      // function
      else if (isFunction(selector)) {
        return $(document).ready(selector);
      }

      // Node
      else if (selector.nodeType || selector === window || selector === document) {
        arr.push(selector);
      }

      // NodeList
      else if (selector.length > 0 && selector[0].nodeType) {
        for (i = 0; i < selector.length; i++) {
          arr.push(selector[i]);
        }
      }

      return new JQ(arr);
    };

    $.fn = JQ.prototype;

    /**
     * 扩展函数和原型属性
     * @param obj
     */
    $.extend = $.fn.extend = function (obj) {
      if (obj === undefined) {
        return this;
      }

      var length = arguments.length;
      var prop;
      var i;
      var options;

      // $.extend(obj)
      if (length === 1) {
        for (prop in obj) {
          if (obj.hasOwnProperty(prop)) {
            this[prop] = obj[prop];
          }
        }

        return this;
      }

      // $.extend({}, defaults[, obj])
      for (i = 1; i < length; i++) {
        options = arguments[i];
        for (prop in options) {
          if (options.hasOwnProperty(prop)) {
            obj[prop] = options[prop];
          }
        }
      }

      return obj;
    };

    $.extend({

      /**
       * 遍历对象
       * @param obj {String|Array|Object}
       * @param callback {Function}
       * @returns {Array|Object}
       */
      each: each,

      /**
       * 合并两个数组,返回的结果会修改第一个数组的内容
       * @param first {Array}
       * @param second {Array}
       * @returns {Array}
       */
      merge: merge,

      /**
       * åˆ é™¤æ•°ç»„ä¸­é‡å¤å…ƒç´
       * @param arr {Array}
       * @returns {Array}
       */
      unique: unique,

      /**
       * 通过遍历集合中的节点对象,通过函数返回一个新的数组,null 或 undefined 将被过滤掉。
       * @param elems
       * @param callback
       * @returns {Array}
       */
      map: map,

      /**
       * 一个 DOM 节点是否包含另一个 DOM 节点
       * @param parent {Node} 父节点
       * @param node {Node} 子节点
       * @returns {Boolean}
       */
      contains: function (parent, node) {
        if (parent && !node) {
          return documentElement.contains(parent);
        }

        return parent !== node && parent.contains(node);
      },

      /**
       * 将数组或对象序列化
       * @param obj
       * @returns {String}
       */
      param: function (obj) {
        if (!isObjectLike(obj)) {
          return '';
        }

        var args = [];
        each(obj, function (key, value) {
          destructure(key, value);
        });

        return args.join('&');

        function destructure(key, value) {
          var keyTmp;

          if (isObjectLike(value)) {
            each(value, function (i, v) {
              if (isArray(value) && !isObjectLike(v)) {
                keyTmp = '';
              } else {
                keyTmp = i;
              }

              destructure(key + '[' + keyTmp + ']', v);
            });
          } else {
            if (!isNull(value) && value !== '') {
              keyTmp = '=' + encodeURIComponent(value);
            } else {
              keyTmp = '';
            }

            args.push(encodeURIComponent(key) + keyTmp);
          }
        }
      },
    });

    $.fn.extend({

      /**
       * 遍历对象
       * @param callback {Function}
       * @return {JQ}
       */
      each: function (callback) {
        return each(this, callback);
      },

      /**
       * 通过遍历集合中的节点对象,通过函数返回一个新的对象,null 或 undefined 将被过滤掉。
       * @param callback {Function}
       * @returns {JQ}
       */
      map: function (callback) {
        return new JQ(map(this, function (el, i) {
          return callback.call(el, i, el);
        }));
      },

      /**
       * 获取指定 DOM å…ƒç´ ï¼Œæ²¡æœ‰ index 参数时,获取所有 DOM 的数组
       * @param index {Number=}
       * @returns {Node|Array}
       */
      get: function (index) {
        return index === undefined ?
          slice.call(this) :
          this[index >= 0 ? index : index + this.length];
      },

      /**
       * array中提取的方法。从start开始,如果end 指出。提取不包含endä½ç½®çš„å…ƒç´ ã€‚
       * @param argument {start, end}
       * @returns {JQ}
       */
      slice: function (argument) {
        return new JQ(slice.apply(this, arguments));
      },

      /**
       * ç­›é€‰å…ƒç´ é›†åˆ
       * @param selector {String|JQ|Node|Function}
       * @returns {JQ}
       */
      filter: function (selector) {
        if (isFunction(selector)) {
          return this.map(function (index, ele) {
            return selector.call(ele, index, ele) ? ele : undefined;
          });
        } else {
          var $selector = $(selector);
          return this.map(function (index, ele) {
            return $selector.index(ele) > -1 ? ele : undefined;
          });
        }
      },

      /**
       * ä»Žå…ƒç´ é›†åˆä¸­åˆ é™¤æŒ‡å®šçš„å…ƒç´
       * @param selector {String|Node|JQ|Function}
       * @return {JQ}
       */
      not: function (selector) {
        var $excludes = this.filter(selector);
        return this.map(function (index, ele) {
          return $excludes.index(ele) > -1 ? undefined : ele;
        });
      },

      /**
       * èŽ·å–å…ƒç´ ç›¸å¯¹äºŽ document 的偏移
       * @returns {Object}
       */
      offset: function () {
        if (this[0]) {
          var offset = this[0].getBoundingClientRect();
          return {
            left: offset.left + window.pageXOffset,
            top: offset.top + window.pageYOffset,
            width: offset.width,
            height: offset.height,
          };
        }

        return null;
      },

      /**
       * 返回最近的用于定位的父元ç´
       * @returns {*|JQ}
       */
      offsetParent: function () {
        return this.map(function () {
          var offsetParent = this.offsetParent;

          while (offsetParent && $(offsetParent).css('position') === 'static') {
            offsetParent = offsetParent.offsetParent;
          }

          return offsetParent || documentElement;
        });
      },

      /**
       * èŽ·å–å…ƒç´ ç›¸å¯¹äºŽçˆ¶å…ƒç´ çš„åç§»
       * @return {Object}
       */
      position: function () {
        var _this = this;

        if (!_this[0]) {
          return null;
        }

        var offsetParent;
        var offset;
        var parentOffset = {
          top: 0,
          left: 0,
        };

        if (_this.css('position') === 'fixed') {
          offset = _this[0].getBoundingClientRect();
        } else {
          offsetParent = _this.offsetParent();
          offset = _this.offset();
          if (!nodeName(offsetParent[0], 'html')) {
            parentOffset = offsetParent.offset();
          }

          parentOffset = {
            top: parentOffset.top + offsetParent.css('borderTopWidth'),
            left: parentOffset.left + offsetParent.css('borderLeftWidth'),
          };
        }

        return {
          top: offset.top - parentOffset.top - _this.css('marginTop'),
          left: offset.left - parentOffset.left - _this.css('marginLeft'),
          width: offset.width,
          height: offset.height,
        };
      },

      /**
       * 显示指定元ç´
       * @returns {JQ}
       */
      show: function () {
        return this.each(function () {
          if (this.style.display === 'none') {
            this.style.display = '';
          }

          if (window.getComputedStyle(this, '').getPropertyValue('display') === 'none') {
            this.style.display = defaultDisplay(this.nodeName);
          }
        });
      },

      /**
       * 隐藏指定元ç´
       * @returns {JQ}
       */
      hide: function () {
        return this.each(function () {
          this.style.display = 'none';
        });
      },

      /**
       * åˆ‡æ¢å…ƒç´ çš„æ˜¾ç¤ºçŠ¶æ€
       * @returns {JQ}
       */
      toggle: function () {
        return this.each(function () {
          this.style.display = this.style.display === 'none' ? '' : 'none';
        });
      },

      /**
       * 是否含有指定的 CSS ç±»
       * @param className {String}
       * @returns {boolean}
       */
      hasClass: function (className) {
        if (!this[0] || !className) {
          return false;
        }

        return this[0].classList.contains(className);
      },

      /**
       * 移除指定属性
       * @param attr {String}
       * @returns {JQ}
       */
      removeAttr: function (attr) {
        return this.each(function () {
          this.removeAttribute(attr);
        });
      },

      /**
       * åˆ é™¤å±žæ€§å€¼
       * @param name {String}
       * @returns {JQ}
       */
      removeProp: function (name) {
        return this.each(function () {
          try {
            delete this[name];
          } catch (e) {}
        });
      },

      /**
       * 获取当前对象中第n个元ç´
       * @param index {Number}
       * @returns {JQ}
       */
      eq: function (index) {
        var ret = index === -1 ? this.slice(index) : this.slice(index, +index + 1);
        return new JQ(ret);
      },

      /**
       * 获取对象中第一个元ç´
       * @returns {JQ}
       */
      first: function () {
        return this.eq(0);
      },

      /**
       * 获取对象中最后一个元ç´
       * @returns {JQ}
       */
      last: function () {
        return this.eq(-1);
      },

      /**
       * èŽ·å–ä¸€ä¸ªå…ƒç´ çš„ä½ç½®ã€‚
       * 当 ele å‚æ•°æ²¡æœ‰ç»™å‡ºæ—¶ï¼Œè¿”å›žå½“å‰å…ƒç´ åœ¨å…„å¼ŸèŠ‚ç‚¹ä¸­çš„ä½ç½®ã€‚
       * 有给出了 ele 参数时,返回 ele å…ƒç´ åœ¨å½“å‰å¯¹è±¡ä¸­çš„ä½ç½®
       * @param ele {Selector|Node=}
       * @returns {Number}
       */
      index: function (ele) {
        if (!ele) {
          // 获取当前 JQ å¯¹è±¡çš„ç¬¬ä¸€ä¸ªå…ƒç´ åœ¨åŒè¾ˆå…ƒç´ ä¸­çš„ä½ç½®
          return this.eq(0).parent().children().get().indexOf(this[0]);
        } else if (isString(ele)) {
          // 返回当前 JQ å¯¹è±¡çš„ç¬¬ä¸€ä¸ªå…ƒç´ åœ¨æŒ‡å®šé€‰æ‹©å™¨å¯¹åº”çš„å…ƒç´ ä¸­çš„ä½ç½®
          return $(ele).eq(0).parent().children().get().indexOf(this[0]);
        } else {
          // è¿”å›žæŒ‡å®šå…ƒç´ åœ¨å½“å‰ JQ 对象中的位置
          return this.get().indexOf(ele);
        }
      },

      /**
       * æ ¹æ®é€‰æ‹©å™¨ã€DOMå…ƒç´ æˆ– JQ å¯¹è±¡æ¥æ£€æµ‹åŒ¹é…å…ƒç´ é›†åˆï¼Œ
       * å¦‚æžœå…¶ä¸­è‡³å°‘æœ‰ä¸€ä¸ªå…ƒç´ ç¬¦åˆè¿™ä¸ªç»™å®šçš„è¡¨è¾¾å¼å°±è¿”å›žtrue
       * @param selector {String|Node|NodeList|Array|JQ|Window}
       * @returns boolean
       */
      is: function (selector) {
        var _this = this[0];

        if (!_this || selector === undefined || selector === null) {
          return false;
        }

        var $compareWith;
        var i;
        if (isString(selector)) {
          if (_this === document || _this === window) {
          &nnbsp; return false;
          }

          var matchesSelector =
            _this.matches ||
            _this.matchesSelector ||
            _this.webkitMatchesSelector ||
            _this.mozMatchesSelector ||
            _this.oMatchesSelector ||
            _this.msMatchesSelector;

          return matchesSelector.call(_this, selector);
        } else if (selector === document || selector === window) {
          return _this === selector;
        } else {
          if (selector.nodeType || isArrayLike(selector)) {
            $compareWith = selector.nodeType ? [selector] : selector;
            for (i = 0; i < $compareWith.length; i++) {
              if ($compareWith[i] === _this) {
                return true;
              }
            }

            return false;
          }

          return false;
        }
      },

      /**
       * æ ¹æ® CSS 选择器找到后代节点的集合
       * @param selector {String}
       * @returns {JQ}
       */
      find: function (selector) {
        var foundElements = [];

        this.each(function (i, _this) {
          merge(foundElements, _this.querySelectorAll(selector));
        });

        return new JQ(foundElements);
      },

      /**
       * æ‰¾åˆ°ç›´æŽ¥å­å…ƒç´ çš„å…ƒç´ é›†åˆ
       * @param selector {String=}
       * @returns {JQ}
       */
      children: function (selector) {
        var children = [];
        this.each(function (i, _this) {
          each(_this.childNodes, function (i, childNode) {
            if (childNode.nodeType !== 1) {
              return true;
            }

            if (!selector || (selector && $(childNode).is(selector))) {
              children.push(childNode);
            }
          });
        });

        return new JQ(unique(children));
      },

      /**
       * ä¿ç•™å«æœ‰æŒ‡å®šå­å…ƒç´ çš„å…ƒç´ ï¼ŒåŽ»æŽ‰ä¸å«æœ‰æŒ‡å®šå­å…ƒç´ çš„å…ƒç´
       * @param selector {String|Node|JQ|NodeList|Array}
       * @return {JQ}
       */
      has: function (selector) {
        var $targets = isString(selector) ? this.find(selector) : $(selector);
        var len = $targets.length;
        return this.filter(function () {
          for (var i = 0; i < len; i++) {
            if ($.contains(this, $targets[i])) {
              return true;
            }
          }
        });
      },

      /**
       * å–å¾—åŒè¾ˆå…ƒç´ çš„é›†åˆ
       * @param selector {String=}
       * @returns {JQ}
       */
      siblings: function (selector) {
        return this.prevAll(selector).add(this.nextAll(selector));
      },

      /**
       * 返回首先匹配到的父节点,包含父节点
       * @param selector {String}
       * @returns {JQ}
       */
      closest: function (selector) {
        var _this = this;

        if (!_this.is(selector)) {
          _this = _this.parents(selector).eq(0);
        }

        return _this;
      },

      /**
       * åˆ é™¤æ‰€æœ‰åŒ¹é…çš„å…ƒç´
       * @returns {JQ}
       */
      remove: function () {
        return this.each(function (i, _this) {
          if (_this.parentNode) {
            _this.parentNode.removeChild(_this);
          }
        });
      },

      /**
       * æ·»åŠ åŒ¹é…çš„å…ƒç´ åˆ°å½“å‰å¯¹è±¡ä¸­
       * @param selector {String|JQ}
       * @returns {JQ}
       */
      add: function (selector) {
        return new JQ(unique(merge(this.get(), $(selector))));
      },

      /**
       * åˆ é™¤å­èŠ‚ç‚¹
       * @returns {JQ}
       */
      empty: function () {
        return this.each(function () {
          this.innerHTML = '';
        });
      },

      /**
       * é€šè¿‡æ·±åº¦å…‹éš†æ¥å¤åˆ¶é›†åˆä¸­çš„æ‰€æœ‰å…ƒç´ ã€‚
       * (通过原生 cloneNode æ–¹æ³•æ·±åº¦å…‹éš†æ¥å¤åˆ¶é›†åˆä¸­çš„æ‰€æœ‰å…ƒç´ ã€‚æ­¤æ–¹æ³•ä¸ä¼šæœ‰æ•°æ®å’Œäº‹ä»¶å¤„ç†ç¨‹åºå¤åˆ¶åˆ°æ–°çš„å…ƒç´ ã€‚è¿™ç‚¹å’Œjquery中利用一个参数来确定是否复制数据和事件处理不相同。)
       * @returns {JQ}
       */
      clone: function () {
        return this.map(function () {
          return this.cloneNode(true);
        });
      },

      /**
       * ç”¨æ–°å…ƒç´ æ›¿æ¢å½“å‰å…ƒç´
       * @param newContent {String|Node|NodeList|JQ}
       * @returns {JQ}
       */
      replaceWith: function (newContent) {
        return this.before(newContent).remove();
      },

      /**
       * å°†è¡¨å•å…ƒç´ çš„å€¼ç»„åˆæˆé”®å€¼å¯¹æ•°ç»„
       * @returns {Array}
       */
      serializeArray: function () {
        var result = [];
        var $ele;
        var type;
        var ele = this[0];

        if (!ele || !ele.elements) {
          return result;
        }

        $(slice.call(ele.elements)).each(function () {
          $ele = $(this);
          type = $ele.attr('type');
          if (
            this.nodeName.toLowerCase() !== 'fieldset' &&
            !this.disabled &&
            ['submit', 'reset', 'button'].indexOf(type) === -1 &&
            (['radio', 'checkbox'].indexOf(type) === -1 || this.checked)
          ) {
            result.push({
              name: $ele.attr('name'),
              value: $ele.val(),
            });
          }
        });

        return result;
      },

      /**
       * å°†è¡¨å•å…ƒç´ æˆ–å¯¹è±¡åºåˆ—åŒ–
       * @returns {String}
       */
      serialize: function () {
        var result = [];
        each(this.serializeArray(), function (i, elm) {
          result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value));
        });

        return result.join('&');
      },
    });

    /**
     * val - èŽ·å–æˆ–è®¾ç½®å…ƒç´ çš„å€¼
     * @param value {String=}
     * @return {*|JQ}
     */
    /**
     * html - èŽ·å–æˆ–è®¾ç½®å…ƒç´ çš„ HTML
     * @param value {String=}
     * @return {*|JQ}
     */
    /**
     * text - èŽ·å–æˆ–è®¾ç½®å…ƒç´ çš„å†…å®¹
     * @param value {String=}
     * @return {*|JQ}
     */
    each(['val', 'html', 'text'], function (nameIndex, name) {
      var props = {
        0: 'value',
        1: 'innerHTML',
        2: 'textContent',
      };

      var defaults = {
        0: undefined,
        1: undefined,
        2: null,
      };

      $.fn[name] = function (value) {
        if (value === undefined) {
          // 获取值
          return this[0] ? this[0][props[nameIndex]] : defaults[nameIndex];
        } else {
          // 设置值
          return this.each(function (i, ele) {
            ele[props[nameIndex]] = value;
          });
        }
      };
    });

    /**
     * attr - èŽ·å–æˆ–è®¾ç½®å…ƒç´ çš„å±žæ€§å€¼
     * @param {name|props|key,value=}
     * @return {String|JQ}
     */
    /**
     * prop - èŽ·å–æˆ–è®¾ç½®å…ƒç´ çš„å±žæ€§å€¼
     * @param {name|props|key,value=}
     * @return {String|JQ}
     */
    /**
     * css - èŽ·å–æˆ–è®¾ç½®å…ƒç´ çš„æ ·å¼
     * @param {name|props|key,value=}
     * @return {String|JQ}
     */
    each(['attr', 'prop', 'css'], function (nameIndex, name) {
      var set = function (ele, key, value) {
        if (nameIndex === 0) {
          ele.setAttribute(key, value);
        } else if (nameIndex === 1) {
          ele[key] = value;
        } else {
          ele.style[key] = value;
        }
      };

      var get = function (ele, key) {
        if (!ele) {
          return undefined;
        }

        var value;
        if (nameIndex === 0) {
          value = ele.getAttribute(key);
        } else if (nameIndex === 1) {
          value = ele[key];
        } else {
          value = window.getComputedStyle(ele, null).getPropertyValue(key);
        }

        return value;
      };

      $.fn[name] = function (key, value) {
        var argLength = arguments.length;

        if (argLength === 1 && isString(key)) {
          // 获取值
          return get(this[0], key);
        } else {
          // 设置值
          return this.each(function (i, ele) {
            if (argLength === 2) {
              set(ele, key, value);
            } else {
              each(key, function (k, v) {
                set(ele, k, v);
              });
            }
          });
        }
      };
    });

    /**
     * addClass - 添加 CSS ç±»ï¼Œå¤šä¸ªç±»åç”¨ç©ºæ ¼åˆ†å‰²
     * @param className {String}
     * @return {JQ}
     */
    /**
     * removeClass - 移除 CSS ç±»ï¼Œå¤šä¸ªç±»åç”¨ç©ºæ ¼åˆ†å‰²
     * @param className {String}
     * @return {JQ}
     */
    /**
     * toggleClass - 切换 CSS ç±»åï¼Œå¤šä¸ªç±»åç”¨ç©ºæ ¼åˆ†å‰²
     * @param className {String}
     * @return {JQ}
     */
    each(['add', 'remove', 'toggle'], function (nameIndex, name) {
      $.fn[name + 'Class'] = function (className) {
        if (!className) {
          return this;
        }

        var classes = className.split(' ');
        return this.each(function (i, ele) {
          each(classes, function (j, cls) {
            ele.classList[name](cls);
          });
        });
      };
    });

    /**
     * width - èŽ·å–å…ƒç´ çš„å®½åº¦
     * @return {Number}
     */
    /**
     * height - èŽ·å–å…ƒç´ çš„é«˜åº¦
     * @return {Number}
     */
    each({
      Width: 'width',
      Height: 'height',
    }, function (prop, name) {
      $.fn[name] = function (val) {
        if (val === undefined) {
          // 获取
          var ele = this[0];

          if (isWindow(ele)) {
            return ele['inner' + prop];
          }

          if (isDocument(ele)) {
            return ele.documentElement['scroll' + prop];
          }

          var $ele = $(ele);

          // IE10、IE11 在 box-sizing:border-box 时,不会包含 padding,这里进行修复
          var IEFixValue = 0;
          if ('ActiveXObject' in window) { // 判断是 IE 浏览器
            if ($ele.css('box-sizing') === 'border-box') {
              IEFixValue =
                parseFloat($ele.css('padding-' + (name === 'width' ? 'left' : 'top'))) +
                parseFloat($ele.css('padding-' + (name === 'width' ? 'right' : 'bottom')));
            }
          }

          return parseFloat($(ele).css(name)) + IEFixValue;
        } else {
          // 设置
          if (!isNaN(Number(val)) && val !== '') {
            val += 'px';
          }

          return this.css(name, val);
        }
      };
    });

    /**
     * innerWidth - èŽ·å–å…ƒç´ çš„å®½åº¦ï¼ŒåŒ…å«å†…è¾¹è·
     * @return {Number}
     */
    /**
     * innerHeight - èŽ·å–å…ƒç´ çš„é«˜åº¦ï¼ŒåŒ…å«å†…è¾¹è·
     * @return {Number}
     */
    each({
      Width: 'width',
      Height: 'height',
    }, function (prop, name) {
      $.fn['inner' + prop] = function () {
        var value = this[name]();
        var $ele = $(this[0]);

        if ($ele.css('box-sizing') !== 'border-box') {
          value += parseFloat($ele.css('padding-' + (name === 'width' ? 'left' : 'top')));
          value += parseFloat($ele.css('padding-' + (name === 'width' ? 'right' : 'bottom')));
        }

        return value;
      };
    });

    var dir = function (nodes, selector, nameIndex, node) {
      var ret = [];
      var ele;
      nodes.each(function (j, _this) {
        ele = _this[node];
        while (ele) {
          if (nameIndex === 2) {
            // prevUntil
            if (!selector || (selector && $(ele).is(selector))) {
              break;
            }

            ret.push(ele);
          } else if (nameIndex === 0) {
            // prev
            if (!selector || (selector && $(ele).is(selector))) {
              ret.push(ele);
            }

            break;
          } else {
            // prevAll
            if (!selector || (selector && $(ele).is(selector))) {
              ret.push(ele);
            }
          }

          ele = ele[node];
        }
      });

      return new JQ(unique(ret));
    };

    /**
     * prev - 取得前一个匹配的元ç´
     * @param selector {String=}
     * @return {JQ}
     */
    /**
     * prevAll - 取得前面所有匹配的元ç´
     * @param selector {String=}
     * @return {JQ}
     */
    /**
     * prevUntil - å–å¾—å‰é¢çš„æ‰€æœ‰å…ƒç´ ï¼Œç›´åˆ°é‡åˆ°åŒ¹é…çš„å…ƒç´ ï¼Œä¸åŒ…å«åŒ¹é…çš„å…ƒç´
     * @param selector {String=}
     * @return {JQ}
     */
    each(['', 'All', 'Until'], function (nameIndex, name) {
      $.fn['prev' + name] = function (selector) {

        // prevAll、prevUntil éœ€è¦æŠŠå…ƒç´ çš„é¡ºåºå€’åºå¤„ç†ï¼Œä»¥ä¾¿å’Œ jQuery 的结果一致
        var $nodes = nameIndex === 0 ? this : $(this.get().reverse());
        return dir($nodes, selector, nameIndex, 'previousElementSibling');
      };
    });

    /**
     * next - 取得后一个匹配的元ç´
     * @param selector {String=}
     * @return {JQ}
     */
    /**
     * nextAll - 取得后面所有匹配的元ç´
     * @param selector {String=}
     * @return {JQ}
     */
    /**
     * nextUntil - å–å¾—åŽé¢æ‰€æœ‰åŒ¹é…çš„å…ƒç´ ï¼Œç›´åˆ°é‡åˆ°åŒ¹é…çš„å…ƒç´ ï¼Œä¸åŒ…å«åŒ¹é…çš„å…ƒç´
     * @param selector {String=}
     * @return {JQ}
     */
    each(['', 'All', 'Until'], function (nameIndex, name) {
      $.fn['next' + name] = function (selector) {
        return dir(this, selector, nameIndex, 'nextElementSibling');
      };
    });

    /**
     * parent - 取得匹配的直接父元ç´
     * @param selector {String=}
     * @return {JQ}
     */
    /**
     * parents - 取得所有匹配的父元ç´
     * @param selector {String=}
     * @return {JQ}
     */
    /**
     * parentUntil - å–å¾—æ‰€æœ‰çš„çˆ¶å…ƒç´ ï¼Œç›´åˆ°é‡åˆ°åŒ¹é…çš„å…ƒç´ ï¼Œä¸åŒ…å«åŒ¹é…çš„å…ƒç´
     * @param selector {String=}
     * @return {JQ}
     */
    each(['', 's', 'sUntil'], function (nameIndex, name) {
      $.fn['parent' + name] = function (selector) {

        // parents、parentsUntil éœ€è¦æŠŠå…ƒç´ çš„é¡ºåºåå‘å¤„ç†ï¼Œä»¥ä¾¿å’Œ jQuery 的结果一致
        var $nodes = nameIndex === 0 ? this : $(this.get().reverse());
        return dir($nodes, selector, nameIndex, 'parentNode');
      };
    });

    /**
     * append - åœ¨å…ƒç´ å†…éƒ¨è¿½åŠ å†…å®¹
     * @param newChild {String|Node|NodeList|JQ}
     * @return {JQ}
     */
    /**
     * prepend - åœ¨å…ƒç´ å†…éƒ¨å‰ç½®å†…å®¹
     * @param newChild {String|Node|NodeList|JQ}
     * @return {JQ}
     */
    each(['append', 'prepend'], function (nameIndex, name) {
      $.fn[name] = function (newChild) {
        var newChilds;
        var copyByClone = this.length > 1;

        if (isString(newChild)) {
          var tempDiv = document.createElement('div');
          tempDiv.innerHTML = newChild;
          newChilds = slice.call(tempDiv.childNodes);
        } else {
          newChilds = $(newChild).get();
        }

        if (nameIndex === 1) {
          // prepend
          newChilds.reverse();
        }

        return this.each(function (i, _this) {
          each(newChilds, function (j, child) {
            // ä¸€ä¸ªå…ƒç´ è¦åŒæ—¶è¿½åŠ åˆ°å¤šä¸ªå…ƒç´ ä¸­ï¼Œéœ€è¦å…ˆå¤åˆ¶ä¸€ä»½ï¼Œç„¶åŽè¿½åŠ
            if (copyByClone && i > 0) {
              child = child.cloneNode(true);
            }

            if (nameIndex === 0) {
              // append
              _this.appendChild(child);
            } else {
              // prepend
              _this.insertBefore(child, _this.childNodes[0]);
            }
          });
        });
      };
    });

    /**
     * insertBefore - æ’å…¥åˆ°æŒ‡å®šå…ƒç´ çš„å‰é¢
     * @param selector {String|Node|NodeList|JQ}
     * @return {JQ}
     */
    /**
     * insertAfter - æ’å…¥åˆ°æŒ‡å®šå…ƒç´ çš„åŽé¢
     * @param selector {String|Node|NodeList|JQ}
     * @return {JQ}
     */
    each(['insertBefore', 'insertAfter'], function (nameIndex, name) {
      $.fn[name] = function (selector) {
        var $ele = $(selector);
        return this.each(function (i, _this) {
          $ele.each(function (j, ele) {
            ele.parentNode.insertBefore(
              $ele.length === 1 ? _this : _this.cloneNode(true),
              nameIndex === 0 ? ele : ele.nextSibling
            );
          });
        });
      };
    });

    /**
     * appendTo - è¿½åŠ åˆ°æŒ‡å®šå…ƒç´ å†…å®¹
     * @param selector {String|Node|NodeList|JQ}
     * @return {JQ}
     */
    /**
     * prependTo - å‰ç½®åˆ°æŒ‡å®šå…ƒç´ å†…éƒ¨
     * @param selector {String|Node|NodeList|JQ}
     * @return {JQ}
     */
    /**
     * before - æ’å…¥åˆ°æŒ‡å®šå…ƒç´ å‰é¢
     * @param selector {String|Node|NodeList|JQ}
     * @return {JQ}
     */
    /**
     * after - æ’å…¥åˆ°æŒ‡å®šå…ƒç´ åŽé¢
     * @param selector {String|Node|NodeList|JQ}
     * @return {JQ}
     */
    /**
     * replaceAll - 替换掉指定元ç´
     * @param selector {String|Node|NodeList|JQ}
     * @return {JQ}
     */
    each({
      appendTo: 'append',
      prependTo: 'prepend',
      before: 'insertBefore',
      after: 'insertAfter',
      replaceAll: 'replaceWith',
    }, function (name, original) {
      $.fn[name] = function (selector) {
        $(selector)[original](this);
        return this;
      };
    });



    (function () {
      var dataNS = 'mduiElementDataStorage';

      $.extend({
        /**
         * åœ¨æŒ‡å®šå…ƒç´ ä¸Šå­˜å‚¨æ•°æ®ï¼Œæˆ–ä»ŽæŒ‡å®šå…ƒç´ ä¸Šè¯»å–æ•°æ®
         * @param ele 必须, DOM å…ƒç´
         * @param key 必须,键名
         * @param value 可选,值
         */
        data: function (ele, key, value) {
          var data = {};

          if (value !== undefined) {
            // æ ¹æ® key、value 设置值
            data[key] = value;
          } else if (isObjectLike(key)) {
            // æ ¹æ®é”®å€¼å¯¹è®¾ç½®å€¼
            data = key;
          } else if (key === undefined) {
            // 获取所有值
            var result = {};
            each(ele.attributes, function (i, attribute) {
              var name = attribute.name;
              if (name.indexOf('data-') === 0) {
                var prop = name.slice(5).replace(/-./g, function (u) {
                  // æ¨ªæ è½¬ä¸ºé©¼å³°æ³•
                  return u.charAt(1).toUpperCase();
                });

                result[prop] = attribute.value;
              }
            });

            if (ele[dataNS]) {
              each(ele[dataNS], function (k, v) {
                result[k] = v;
              });
            }

            return result;
          } else {
            // 获取指定值
            if (ele[dataNS] && (key in ele[dataNS])) {
              return ele[dataNS][key];
            } else {
              var dataKey = ele.getAttribute('data-' + key);
              if (dataKey) {
                return dataKey;
              } else {
                return undefined;
              }
            }
          }

          // 设置值
          if (!ele[dataNS]) {
            ele[dataNS] = {};
          }

          each(data, function (k, v) {
            ele[dataNS][k] = v;
          });
        },

        /**
         * ç§»é™¤æŒ‡å®šå…ƒç´ ä¸Šå­˜æ”¾çš„æ•°æ®
         * @param ele 必须,DOM å…ƒç´
         * @param key 必须,键名
         */
        removeData: function (ele, key) {
          if (ele[dataNS] && ele[dataNS][key]) {
            ele[dataNS][key] = null;
            delete ele.mduiElementDataStorage[key];
          }
        },

      });

      $.fn.extend({

        /**
         * åœ¨å…ƒç´ ä¸Šè¯»å–æˆ–è®¾ç½®æ•°æ®
         * @param key å¿…é¡»
         * @param value
         * @returns {*}
         */
        data: function (key, value) {
          if (value === undefined) {
            // 获取值
            if (this[0]) {
              return $.data(this[0], key);
            } else {
              return undefined;
            }
          } else {
            // 设置值
            return this.each(function (i, ele) {
              $.data(ele, key, value);
            });
          }
        },

        /**
         * ç§»é™¤å…ƒç´ ä¸Šå­˜å‚¨çš„æ•°æ®
         * @param key å¿…é¡»
         * @returns {*}
         */
        removeData: function (key) {
          return this.each(function (i, ele) {
            $.removeData(ele, key);
          });
        },

      });
    })();


    (function () {
      // 存储事件
      var handlers = {
        // i: { // å…ƒç´ ID
        //   j: { // 事件ID
        //     e: 事件名
        //     fn: 事件处理函数
        //     i: 事件ID
        //     proxy:
        //     sel: 选择器
        //   }
        // }
      };

      // å…ƒç´ ID
      var _elementId = 1;

      var fnFalse = function () {
        return false;
      };

      $.fn.extend({
        /**
         * DOM åŠ è½½å®Œæ¯•åŽè°ƒç”¨çš„å‡½æ•°
         * @param callback
         * @returns {ready}
         */
        ready: function (callback) {
          if (/complete|loaded|interactive/.test(document.readyState) && document.body) {
            callback($);
          } else {
            document.addEventListener('DOMContentLoaded', function () {
              callback($);
            }, false);
          }

          return this;
        },

        /**
         * 绑定事件
         *
         * $().on({eventName: fn}, selector, data);
         * $().on({eventName: fn}, selector)
         * $().on({eventName: fn})
         * $().on(eventName, selector, data, fn);
         * $().on(eventName, selector, fn);
         * $().on(eventName, data, fn);
         * $().on(eventName, fn);
         * $().on(eventName, false);
         *
         * @param eventName
         * @param selector
         * @param data
         * @param callback
         * @param one 是否是 one 方法,只在 JQ 内部使用
         * @returns
         */
        on: function (eventName, selector, data, callback, one) {
          var _this = this;

          // 默认
          // $().on(event, selector, data, callback)

          // event 使用 事件:函数 键值对
          // event = {
          //   'event1': callback1,
          //   'event2': callback2
          // }
          //
          // $().on(event, selector, data)
          if (eventName && !isString(eventName)) {
            each(eventName, function (type, fn) {
              _this.on(type, selector, data, fn);
            });

            return _this;
          }

          // selector 不存在
          // $().on(event, data, callback)
          if (!isString(selector) && !isFunction(callback) && callback !== false) {
            callback = data;
            data = selector;
            selector = undefined;
          }

          // data 不存在
          // $().on(event, callback)
          if (isFunction(data) || data === false) {
            callback = data;
            data = undefined;
          }

          // callback 为 false
          // $().on(event, false)
          if (callback === false) {
            callback = fnFalse;
          }

          if (one === 1) {
            var origCallback = callback;
            callback = function () {
              _this.off(eventName, selector, callback);
              return origCallback.apply(this, arguments);
            };
          }

          return this.each(function () {
            add(this, eventName, callback, data, selector);
          });
        },

        /**
         * 绑定事件,只触发一次
         * @param eventName
         * @param selector
         * @param data
         * @param callback
         */
        one: function (eventName, selector, data, callback) {
          var _this = this;

          if (!isString(eventName)) {
            each(eventName, function (type, fn) {
              type.split(' ').forEach(function (eName) {
                _this.on(eName, selector, data, fn, 1);
              });
            });
          } else {
            eventName.split(' ').forEach(function (eName) {
              _this.on(eName, selector, data, callback, 1);
            });
          }

          return this;
        },

        /**
         * 取消绑定事件
         *
         * $().off(eventName, selector);
         * $().off(eventName, callback);
         * $().off(eventName, false);
         *
         */
        off: function (eventName, selector, callback) {
          var _this = this;

          // event 使用 事件:函数 键值对
          // event = {
          //   'event1': callback1,
          //   'event2': callback2
          // }
          //
          // $().off(event, selector)
          if (eventName && !isString(eventName)) {
            each(eventName, function (type, fn) {
              _this.off(type, selector, fn);
            });

            return _this;
          }

          // selector 不存在
          // $().off(event, callback)
          if (!isString(selector) && !isFunction(callback) && callback !== false) {
            callback = selector;
            selector = undefined;
          }

          // callback 为 false
          // $().off(event, false)
          if (callback === false) {
            callback = fnFalse;
          }

          return _this.each(function () {
            remove(this, eventName, callback, selector);
          });
        },

        /**
         * 触发一个事件
         * @param eventName
         * @param data
         * @returns {*|JQ}
         */
        trigger: function (eventName, data) {
          if (!isString(eventName)) {
            return;
          }

          var evt;
          try {
            evt = new CustomEvent(eventName, { detail: data, bubbles: true, cancelable: true });
          } catch (e) {
            evt = document.createEvent('Event');
            evt.initEvent(eventName, true, true);
            evt.detail = data;
          }

          evt._data = data;

          return this.each(function () {
            this.dispatchEvent(evt);
          });
        },
      });

      /**
       * æ·»åŠ äº‹ä»¶ç›‘å¬
       * @param element
       * @param eventName
       * @param func
       * @param data
       * @param selector
       */
      function add(element, eventName, func, data, selector) {
        var elementId = getElementId(element);
        if (!handlers[elementId]) {
          handlers[elementId] = [];
        }

        // ä¼ å…¥ data.useCapture 来设置 useCapture: true
        var useCapture = false;
        if (isObjectLike(data) && data.useCapture) {
          useCapture = true;
        }

        eventName.split(' ').forEach(function (event) {

          var handler = {
            e: event,
            fn: func,
            sel: selector,
            i: handlers[elementId].length,
          };

          var callFn = function (e, ele) {
            var result = func.apply(ele, e._data === undefined ? [e] : [e].concat(e._data));
            if (result === false) {
              e.preventDefault();
              e.stopPropagation();
            }
          };

          var proxyfn = handler.proxy = function (e) {
            e.data = data;

            // 事件代理
            if (selector) {
              $(element).find(selector).get().reverse().forEach(function (ele) {
                if (ele === e.target || $.contains(ele, e.target)) {
                  callFn(e, ele);
                }
              });
            }

            // 不使用事件代理
            else {
              callFn(e, element);
            }
          };

          handlers[elementId].push(handler);
          element.addEventListener(handler.e, proxyfn, useCapture);
        });
      }

      /**
       * 移除事件监听
       * @param element
       * @param eventName
       * @param func
       * @param selector
       */
      function remove(element, eventName, func, selector) {
        (eventName || '').split(' ').forEach(function (event) {
          getHandlers(element, event, func, selector).forEach(function (handler) {
            delete handlers[getElementId(element)][handler.i];
            element.removeEventListener(handler.e, handler.proxy, false);
          });
        });
      }

      /**
       * ä¸ºå…ƒç´ èµ‹äºˆä¸€ä¸ªå”¯ä¸€çš„ID
       * @param element
       * @returns {number|*}
       */
      function getElementId(element) {
        return element._elementId || (element._elementId = _elementId++);
      }

      /**
       * 获取匹配的事件
       * @param element
       * @param eventName
       * @param func
       * @param selector
       * @returns {Array.<T>}
       */
      function getHandlers(element, eventName, func, selector) {
        return (handlers[getElementId(element)] || []).filter(function (handler) {

          return handler &&
            (!eventName  || handler.e === eventName) &&
            (!func || handler.fn.toString() === func.toString()) &&
            (!selector || handler.sel === selector);
        });
      }

    })();


  /* jshint ignore:start */
    return $;
  })(window, document);
  /* jshint ignore:end */


  /**
   * =============================================================================
   * ************   å®šä¹‰å…¨å±€å˜é‡   ************
   * =============================================================================
   */

  var $body = $('body');
  var $document = $(document);
  var $window = $(window);

  /**
   * 队列 -- 当前队列的 api å’Œ jquery ä¸ä¸€æ ·ï¼Œæ‰€ä»¥ä¸æ‰“åŒ…è¿› mdui.JQ 里
   */
  var queue = {};
  (function () {
    var queueData = [];

    /**
     * 写入队列
     * @param queueName 对列名
     * @param func 函数名,该参数为空时,返回所有队列
     */
    queue.queue = function (queueName, func) {
      if (queueData[queueName] === undefined) {
        queueData[queueName] = [];
      }

      if (func === undefined) {
        return queueData[queueName];
      }

      queueData[queueName].push(func);
    };

    /**
     * 从队列中移除第一个函数,并执行该函数
     * @param queueName
     */
    queue.dequeue = function (queueName) {
      if (queueData[queueName] !== undefined && queueData[queueName].length) {
        (queueData[queueName].shift())();
      }
    };

  })();

  /**
   * touch 事件后的 500ms 内禁用 mousedown 事件
   *
   * 不支持触控的屏幕上事件顺序为 mousedown -> mouseup -> click
   * 支持触控的屏幕上事件顺序为 touchstart -> touchend -> mousedown -> mouseup -> click
   */
  var TouchHandler = {
    touches: 0,

    /**
     * 该事件是否被允许
     * 在执行事件前调用该方法判断事件是否可以执行
     * @param e
     * @returns {boolean}
     */
    isAllow: function (e) {
      var allow = true;

      if (
        TouchHandler.touches &&
        [
          'mousedown',
          'mouseup',
          'mousemove',
          'click',
          'mouseover',
          'mouseout',
          'mouseenter',
          'mouseleave',
        ].indexOf(e.type) > -1
      ) {
        // 触发了 touch äº‹ä»¶åŽé˜»æ­¢é¼ æ ‡äº‹ä»¶
        allow = false;
      }

      return allow;
    },

    /**
     * 在 touchstart å’Œ touchmove、touchend、touchcancel 事件中调用该方法注册事件
     * @param e
     */
    register: function (e) {
      if (e.type === 'touchstart') {
        // 触发了 touch 事件
        TouchHandler.touches += 1;
      } else if (['touchmove', 'touchend', 'touchcancel'].indexOf(e.type) > -1) {
        // touch 事件结束 500ms åŽè§£é™¤å¯¹é¼ æ ‡äº‹ä»¶çš„é˜»æ­¢
        setTimeout(function () {
          if (TouchHandler.touches) {
            TouchHandler.touches -= 1;
          }
        }, 500);
      }
    },

    start: 'touchstart mousedown',
    move: 'touchmove mousemove',
    end: 'touchend mouseup',
    cancel: 'touchcancel mouseleave',
    unlock: 'touchend touchmove touchcancel',
  };

  // 测试事件
  // 在每一个事件中都使用 TouchHandler.isAllow(e) 判断事件是否可执行
  // 在 touchstart å’Œ touchmove、touchend、touchcancel
  // (function () {
  //
  //   $document
  //     .on(TouchHandler.start, function (e) {
  //       if (!TouchHandler.isAllow(e)) {
  //         return;
  //       }
  //       TouchHandler.register(e);
  //       console.log(e.type);
  //     })
  //     .on(TouchHandler.move, function (e) {
  //       if (!TouchHandler.isAllow(e)) {
  //         return;
  //       }
  //       console.log(e.type);
  //     })
  //     .on(TouchHandler.end, function (e) {
  //       if (!TouchHandler.isAllow(e)) {
  //         return;
  //       }
  //       console.log(e.type);
  //     })
  //     .on(TouchHandler.unlock, TouchHandler.register);
  // })();

  $(function () {
    // é¿å…é¡µé¢åŠ è½½å®ŒåŽç›´æŽ¥æ‰§è¡Œcss动画
    // https://css-tricks.com/transitions-only-after-page-load/

    setTimeout(function () {
      $body.addClass('mdui-loaded');
    }, 0);
  });


  /**
   * =============================================================================
   * ************   MDUI 内部使用的函数   ************
   * =============================================================================
   */

  /**
   * 解析 DATA API 的参数
   * @param str
   * @returns {*}
   */
  var parseOptions = function (str) {
    var options = {};

    if (str === null || !str) {
      return options;
    }

    if (typeof str === 'object') {
      return str;
    }

    /* jshint ignore:start */
    var start = str.indexOf('{');
    try {
      options = (new Function('',
        'var json = ' + str.substr(start) +
        '; return JSON.parse(JSON.stringify(json));'))();
    } catch (e) {
    }
    /* jshint ignore:end */

    return options;
  };

  /**
   * 绑定组件的事件
   * @param eventName 事件名
   * @param pluginName 插件名
   * @param inst 插件实例
   * @param trigger åœ¨è¯¥å…ƒç´ ä¸Šè§¦å‘
   * @param obj 事件参数
   */
  var componentEvent = function (eventName, pluginName, inst, trigger, obj) {
    if (!obj) {
      obj = {};
    }

    obj.inst = inst;

    var fullEventName = eventName + '.mdui.' + pluginName;

    // jQuery 事件
    if (typeof jQuery !== 'undefined') {
      jQuery(trigger).trigger(fullEventName, obj);
    }

    // JQ 事件
    $(trigger).trigger(fullEventName, obj);
  };


  /**
   * =============================================================================
   * ************   å¼€æ”¾çš„常用方法   ************
   * =============================================================================
   */

  $.fn.extend({

    /**
     * 执行强制重绘
     */
    reflow: function () {
      return this.each(function () {
        return this.clientLeft;
      });
    },

    /**
     * 设置 transition 时间
     * @param duration
     */
    transition: function (duration) {
      if (typeof duration !== 'string') {
        duration = duration + 'ms';
      }

      return this.each(function () {
        this.style.webkitTransitionDuration = duration;
        this.style.transitionDuration = duration;
      });
    },

    /**
     * transition 动画结束回调
     * @param callback
     * @returns {transitionEnd}
     */
    transitionEnd: function (callback) {
      var events = [
          'webkitTransitionEnd',
          'transitionend',
        ];
      var i;
      var _this = this;

      function fireCallBack(e) {
        if (e.target !== this) {
          return;
        }

        callback.call(this, e);

        for (i = 0; i < events.length; i++) {
          _this.off(events[i], fireCallBack);
        }
      }

      if (callback) {
        for (i = 0; i < events.length; i++) {
          _this.on(events[i], fireCallBack);
        }
      }

      return this;
    },

    /**
     * 设置 transform-origin 属性
     * @param transformOrigin
     */
    transformOrigin: function (transformOrigin) {
      return this.each(function () {
        this.style.webkitTransformOrigin = transformOrigin;
        this.style.transformOrigin = transformOrigin;
      });
    },

    /**
     * 设置 transform 属性
     * @param transform
     */
    transform: function (transform) {
      return this.each(function () {
        this.style.webkitTransform = transform;
        this.style.transform = transform;
      });
    },

  });

  $.extend({
    /**
     * 创建并显示遮罩
     * @param zIndex 遮罩层的 z-index
     */
    showOverlay: function (zIndex) {
      var $overlay = $('.mdui-overlay');

      if ($overlay.length) {
        $overlay.data('isDeleted', 0);

        if (zIndex !== undefined) {
          $overlay.css('z-index', zIndex);
        }
      } else {
        if (zIndex === undefined) {
          zIndex = 2000;
        }

        $overlay = $('<div class="mdui-overlay">')
          .appendTo($body)
          .reflow()
          .css('z-index', zIndex);
      }

      var level = $overlay.data('overlay-level') || 0;
      return $overlay
        .data('overlay-level', ++level)
        .addClass('mdui-overlay-show');
    },

    /**
     * 隐藏遮罩层
     * @param force 是否强制隐藏遮罩
     */
    hideOverlay: function (force) {
      var $overlay = $('.mdui-overlay');

      if (!$overlay.length) {
        return;
      }

      var level = force ? 1 : $overlay.data('overlay-level');
      if (level > 1) {
        $overlay.data('overlay-level', --level);
        return;
      }

      $overlay
        .data('overlay-level', 0)
        .removeClass('mdui-overlay-show')
        .data('isDeleted', 1)
        .transitionEnd(function () {
          if ($overlay.data('isDeleted')) {
            $overlay.remove();
          }
        });
    },

    /**
     * 锁定屏幕
     */
    lockScreen: function () {
      // 不直接把 body 设为 box-sizing: border-boxï¼Œé¿å…æ±¡æŸ“å…¨å±€æ ·å¼
      var newBodyWidth = $body.width();

      $body
        .addClass('mdui-locked')
        .width(newBodyWidth);

      var level = $body.data('lockscreen-level') || 0;
      $body.data('lockscreen-level', ++level);
    },

    /**
     * 解除屏幕锁定
     * @param force 是否强制解锁屏幕
     */
    unlockScreen: function (force) {
      var level = force ? 1 : $body.data('lockscreen-level');
      if (level > 1) {
        $body.data('lockscreen-level', --level);
        return;
      }

      $body
        .data('lockscreen-level', 0)
        .removeClass('mdui-locked')
        .width('');
    },

    /**
     * 函数节流
     * @param fn
     * @param delay
     * @returns {Function}
     */
    throttle: function (fn, delay) {
      var timer = null;
      if (!delay || delay < 16) {
        delay = 16;
      }

      return function () {
        var _this = this;
        var args = arguments;

        if (timer === null) {
          timer = setTimeout(function () {
            fn.apply(_this, args);
            timer = null;
          }, delay);
        }
      };
    },

    /**
     * 生成唯一 id
     * @param pluginName æ’ä»¶åï¼Œè‹¥ä¼ å…¥è¯¥å‚æ•°ï¼Œguid 将以该参数作为前缀
     * @returns {string}
     */
    guid: function (pluginName) {
      function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
          .toString(16)
          .substring(1);
      }

      var guid = s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
      if (pluginName) {
        guid = 'mdui-' + pluginName + '-' + guid;
      }

      return guid;
    },

  });


  /**
   * =============================================================================
   * ************   Headroom.js   ************
   * =============================================================================
   */

  mdui.Headroom = (function () {

    /**
     * 默认参数
     * @type {{}}
     */
    var DEFAULT = {
      tolerance: 5,                                 // æ»šåŠ¨æ¡æ»šåŠ¨å¤šå°‘è·ç¦»å¼€å§‹éšè—æˆ–æ˜¾ç¤ºå…ƒç´ ï¼Œ{down: num, up: num},或数字
      offset: 0,                                    // 在页面顶部多少距离内滚动不会隐藏元ç´
      initialClass: 'mdui-headroom',                // åˆå§‹åŒ–æ—¶æ·»åŠ çš„ç±»
      pinnedClass: 'mdui-headroom-pinned-top',      // å…ƒç´ å›ºå®šæ—¶æ·»åŠ çš„ç±»
      unpinnedClass: 'mdui-headroom-unpinned-top',  // å…ƒç´ éšè—æ—¶æ·»åŠ çš„ç±»
    };

    /**
     * Headroom
     * @param selector
     * @param opts
     * @constructor
     */
    function Headroom(selector, opts) {
      var _this = this;

      _this.$headroom = $(selector).eq(0);
      if (!_this.$headroom.length) {
        return;
      }

      // 已通过自定义属性实例化过,不再重复实例化
      var oldInst = _this.$headroom.data('mdui.headroom');
      if (oldInst) {
        return oldInst;
      }

      _this.options = $.extend({}, DEFAULT, (opts || {}));

      // 数值转为 {down: bum, up: num}
      var tolerance = _this.options.tolerance;
      if (tolerance !== Object(tolerance)) {
        _this.options.tolerance = {
          down: tolerance,
          up: tolerance,
        };
      }

      _this._init();
    }

    /**
     * 初始化
     * @private
     */
    Headroom.prototype._init = function () {
      var _this = this;

      _this.state = 'pinned';
      _this.$headroom
        .addClass(_this.options.initialClass)
        .removeClass(_this.options.pinnedClass + ' ' + _this.options.unpinnedClass);

      _this.inited = false;
      _this.lastScrollY = 0;

      _this._attachEvent();
    };

    /**
     * 监听滚动事件
     * @private
     */
    Headroom.prototype._attachEvent = function () {
      var _this = this;

      if (!_this.inited) {
        _this.lastScrollY = window.pageYOffset;
        _this.inited = true;

        $window.on('scroll', function () {
          _this._scroll();
        });
      }
    };

    /**
     * 滚动时的处理
     * @private
     */
    Headroom.prototype._scroll = function () {
      var _this = this;
      _this.rafId = window.requestAnimationFrame(function () {
        var currentScrollY = window.pageYOffset;
        var direction = currentScrollY > _this.lastScrollY ? 'down' : 'up';
        var toleranceExceeded =
          Math.abs(currentScrollY - _this.lastScrollY) >=
          _this.options.tolerance[direction];

        if (
          currentScrollY > _this.lastScrollY &&
          currentScrollY >= _this.options.offset &&
          toleranceExceeded) {
          _this.unpin();
        } else if (
          (currentScrollY < _this.lastScrollY && toleranceExceeded) ||
          currentScrollY <= _this.options.offset
        ) {
          _this.pin();
        }

        _this.lastScrollY = currentScrollY;
      });
    };

    /**
     * 动画结束回调
     * @param inst
     */
    var transitionEnd = function (inst) {
      if (inst.state === 'pinning') {
        inst.state = 'pinned';
        componentEvent('pinned', 'headroom', inst, inst.$headroom);
      }

      if (inst.state === 'unpinning') {
        inst.state = 'unpinned';
        componentEvent('unpinned', 'headroom', inst, inst.$headroom);
      }
    };

    /**
     * 固定住
     */
    Headroom.prototype.pin = function () {
      var _this = this;

      if (
        _this.state === 'pinning' ||
        _this.state === 'pinned' ||
        !_this.$headroom.hasClass(_this.options.initialClass)
      ) {
        return;
      }

      componentEvent('pin', 'headroom', _this, _this.$headroom);

      _this.state = 'pinning';

      _this.$headroom
        .removeClass(_this.options.unpinnedClass)
        .addClass(_this.options.pinnedClass)
        .transitionEnd(function () {
          transitionEnd(_this);
        });
    };

    /**
     * 不固定住
     */
    Headroom.prototype.unpin = function () {
      var _this = this;

      if (
        _this.state === 'unpinning' ||
        _this.state === 'unpinned' ||
        !_this.$headroom.hasClass(_this.options.initialClass)
      ) {
        return;
      }

      componentEvent('unpin', 'headroom', _this, _this.$headroom);

      _this.state = 'unpinning';

      _this.$headroom
        .removeClass(_this.options.pinnedClass)
        .addClass(_this.options.unpinnedClass)
        .transitionEnd(function () {
          transitionEnd(_this);
        });
    };

    /**
     * 启用
     */
    Headroom.prototype.enable = function () {
      var _this = this;

      if (!_this.inited) {
        _this._init();
      }
    };

    /**
     * 禁用
     */
    Headroom.prototype.disable = function () {
      var _this = this;

      if (_this.inited) {
        _this.inited = false;
        _this.$headroom
          .removeClass([
            _this.options.initialClass,
            _this.options.pinnedClass,
            _this.options.unpinnedClass,
          ].join(' '));

        $window.off('scroll', function () {
          _this._scroll();
        });

        window.cancelAnimationFrame(_this.rafId);
      }
    };

    /**
     * 获取当前状态 pinning | pinned | unpinning | unpinned
     */
    Headroom.prototype.getState = function () {
      return this.state;
    };

    return Headroom;

  })();


  /**
   * =============================================================================
   * ************   Headroom 自定义属性 API   ************
   * =============================================================================
   */

  $(function () {
    $('[mdui-headroom]').each(function () {
      var $this = $(this);
      var options = parseOptions($this.attr('mdui-headroom'));

      var inst = $this.data('mdui.headroom');
      if (!inst) {
        inst = new mdui.Headroom($this, options);
        $this.data('mdui.headroom', inst);
      }
    });
  });


  /**
   * =============================================================================
   * ************   ä¾› Collapse、 Panel è°ƒç”¨çš„æŠ˜å å†…å®¹å—æ’ä»¶   ************
   * =============================================================================
   */
  var CollapsePrivate = (function () {

    /**
     * 默认参数
     */
    var DEFAULT = {
      accordion: false,                             // 是否使用手风琴效果
    };

    // 类名
    var CLASS = {
      item: 'mdui-collapse-item',           // item 类名
      itemOpen: 'mdui-collapse-item-open',  // 打开状态的 item
      header: 'mdui-collapse-item-header',  // item 中的 header 类名
      body: 'mdui-collapse-item-body',      // item 中的 body 类名
    };

    // 命名空间
    var NAMESPACE = 'collapse';

    /**
     * æŠ˜å å†…å®¹å—
     * @param selector
     * @param opts
     * @param classes
     * @param namespace
     * @constructor
     */
    function Collapse(selector, opts, classes, namespace) {
      var _this = this;

      _this.classes = $.extend({}, CLASS, classes || {});
      _this.namespace = namespace ? namespace : NAMESPACE;

      // æŠ˜å é¢æ¿å…ƒç´
      _this.$collapse = $(selector).eq(0);
      if (!_this.$collapse.length) {
        return;
      }

      // 已通过自定义属性实例化过,不再重复实例化
      var oldInst = _this.$collapse.data('mdui.' + _this.namespace);
      if (oldInst) {
        return oldInst;
      }

      _this.options = $.extend({}, DEFAULT, (opts || {}));

      _this.$collapse.on('click', '.' + _this.classes.header, function () {
        var $item = $(this).parent('.' + _this.classes.item);
        if (_this.$collapse.children($item).length) {
          _this.toggle($item);
        }
      });
    }

    /**
     * 指定 item 是否处于打开状态
     * @param $item
     * @returns {boolean}
     * @private
     */
    Collapse.prototype._isOpen = function ($item) {
      return $item.hasClass(this.classes.itemOpen);
    };

    /**
     * 获取指定 item
     * @param item
     * @returns {*}
     * @private
     */
    Collapse.prototype._getItem = function (item) {
      var _this = this;

      if (parseInt(item) === item) {
        // item 是索引号
        return _this.$collapse.children('.' + _this.classes.item).eq(item);
      }

      return $(item).eq(0);
    };

    /**
     * 动画结束回调
     * @param inst
     * @param $content
     * @param $item
     */
    var transitionEnd = function (inst, $content, $item) {
      if (inst._isOpen($item)) {
        $content
          .transition(0)
          .height('auto')
          .reflow()
          .transition('');

        componentEvent('opened', inst.namespace, inst, $item[0]);
      } else {
        $content.height('');

        componentEvent('closed', inst.namespace, inst, $item[0]);
      }
    };

    /**
     * 打开指定面板项
     * @param item 面板项的索引号或 DOM å…ƒç´ æˆ– CSS 选择器
     */
    Collapse.prototype.open = function (item) {
      var _this = this;
      var $item = _this._getItem(item);

      if (_this._isOpen($item)) {
        return;
      }

      // 关闭其他项
      if (_this.options.accordion) {
        _this.$collapse.children('.' + _this.classes.itemOpen).each(function () {
          var $tmpItem = $(this);

          if ($tmpItem !== $item) {
            _this.close($tmpItem);
          }
        });
      }

      var $content = $item.children('.' + _this.classes.body);

      $content
        .height($content[0].scrollHeight)
        .transitionEnd(function () {
          transitionEnd(_this, $content, $item);
        });

      componentEvent('open', _this.namespace, _this, $item[0]);

      $item.addClass(_this.classes.itemOpen);
    };

    /**
     * 关闭指定项
     * @param item 面板项的索引号或 DOM å…ƒç´ æˆ– CSS 选择器
     */
    Collapse.prototype.close = function (item) {
      var _this = this;
      var $item = _this._getItem(item);

      if (!_this._isOpen($item)) {
        return;
      }

      var $content = $item.children('.' + _this.classes.body);

      componentEvent('close', _this.namespace, _this, $item[0]);

      $item.removeClass(_this.classes.itemOpen);

      $content
        .transition(0)
        .height($content[0].scrollHeight)
        .reflow()
        .transition('')
        .height('')
        .transitionEnd(function () {
          transitionEnd(_this, $content, $item);
        });
    };

    /**
     * 切换指定项的状态
     * @param item 面板项的索引号或 DOM å…ƒç´ æˆ– CSS 选择器或 JQ 对象
     */
    Collapse.prototype.toggle = function (item) {
      var _this = this;
      var $item = _this._getItem(item);

      if (_this._isOpen($item)) {
        _this.close($item);
      } else {
        _this.open($item);
      }
    };

    /**
     * 打开所有项
     */
    Collapse.prototype.openAll = function () {
      var _this = this;

      _this.$collapse.children('.' + _this.classes.item).each(function () {
        var $tmpItem = $(this);

        if (!_this._isOpen($tmpItem)) {
          _this.open($tmpItem);
        }
      });
    };

    /**
     * 关闭所有项
     */
    Collapse.prototype.closeAll = function () {
      var _this = this;

      _this.$collapse.children('.' + _this.classes.item).each(function () {
        var $tmpItem = $(this);

        if (_this._isOpen($tmpItem)) {
          _this.close($tmpItem);
        }
      });
    };

    return Collapse;
  })();

  /**
   * =============================================================================
   * ************   Collapse æŠ˜å å†…å®¹å—æ’ä»¶   ************
   * =============================================================================
   */
  mdui.Collapse = (function () {

    function Collapse(selector, opts) {
      return new CollapsePrivate(selector, opts);
    }

    return Collapse;
  })();


  /**
   * =============================================================================
   * ************   Collapse 自定义属性   ************
   * =============================================================================
   */

  $(function () {
    $('[mdui-collapse]').each(function () {
      var $this = $(this);
      var options = parseOptions($this.attr('mdui-collapse'));

      var inst = $this.data('mdui.collapse');
      if (!inst) {
        inst = new mdui.Collapse($this, options);
        $this.data('mdui.collapse', inst);
      }
    });
  });


  /**
   * =============================================================================
   * ************   Table è¡¨æ ¼   ************
   * =============================================================================
   */

  (function () {

    /**
     * 生成 checkbox çš„ HTML 结构
     * @param tag
     * @returns {string}
     */
    var checkboxHTML = function (tag) {
      return '<' + tag + ' class="mdui-table-cell-checkbox">' +
               '<label class="mdui-checkbox">' +
                 '<input type="checkbox"/>' +
                 '<i class="mdui-checkbox-icon"></i>' +
               '</label>' +
             '</' + tag + '>';
    };

    /**
     * Table è¡¨æ ¼
     * @param selector
     * @constructor
     */
    function Table(selector) {
      var _this = this;

      _this.$table = $(selector).eq(0);

      if (!_this.$table.length) {
        return;
      }

      _this.init();
    }

    /**
     * 初始化
     */
    Table.prototype.init = function () {
      var _this = this;

      _this.$thRow = _this.$table.find('thead tr');
      _this.$tdRows = _this.$table.find('tbody tr');
      _this.$tdCheckboxs = $();
      _this.selectable = _this.$table.hasClass('mdui-table-selectable');
      _this.selectedRow = 0;

      _this._updateThCheckbox();
      _this._updateTdCheckbox();
      _this._updateNumericCol();
    };

    /**
     * æ›´æ–°è¡¨æ ¼è¡Œçš„ checkbox
     */
    Table.prototype._updateTdCheckbox = function () {
      var _this = this;

      _this.$tdRows.each(function () {
        var $tdRow = $(this);

        // 移除旧的 checkbox
        $tdRow.find('.mdui-table-cell-checkbox').remove();

        if (!_this.selectable) {
          return;
        }

        // 创建 DOM
        var $checkbox = $(checkboxHTML('td'))
          .prependTo($tdRow)
          .find('input[type="checkbox"]');

        // 默认选中的行
        if ($tdRow.hasClass('mdui-table-row-selected')) {
          $checkbox[0].checked = true;
          _this.selectedRow++;
        }

        // 所有行都选中后,选中表头;否则,不选中表头
        _this.$thCheckbox[0].checked = _this.selectedRow === _this.$tdRows.length;

        // 绑定事件
        $checkbox.on('change', function () {
          if ($checkbox[0].checked) {
            $tdRow.addClass('mdui-table-row-selected');
            _this.selectedRow++;
          } else {
            $tdRow.removeClass('mdui-table-row-selected');
            _this.selectedRow--;
          }

          // 所有行都选中后,选中表头;否则,不选中表头
          _this.$thCheckbox[0].checked = _this.selectedRow === _this.$tdRows.length;
        });

        _this.$tdCheckboxs = _this.$tdCheckboxs.add($checkbox);
      });
    };

    /**
     * 更新表头的 checkbox
     */
    Table.prototype._updateThCheckbox = function () {
      var _this = this;

      // 移除旧的 checkbox
      _this.$thRow.find('.mdui-table-cell-checkbox').remove();

      if (!_this.selectable) {
        return;
      }

      _this.$thCheckbox = $(checkboxHTML('th'))
        .prependTo(_this.$thRow)
        .find('input[type="checkbox"]')
        .on('change', function () {

          var isCheckedAll = _this.$thCheckbox[0].checked;
          _this.selectedRow = isCheckedAll ? _this.$tdRows.length : 0;

          _this.$tdCheckboxs.each(function (i, checkbox) {
            checkbox.checked = isCheckedAll;
          });

          _this.$tdRows.each(function (i, row) {
            $(row)[isCheckedAll ? 'addClass' : 'removeClass']('mdui-table-row-selected');
          });

        });
    };

    /**
     * 更新数值列
     */
    Table.prototype._updateNumericCol = function () {
      var _this = this;
      var $th;
      var $tdRow;

      _this.$thRow.find('th').each(function (i, th) {
        $th = $(th);

        _this.$tdRows.each(function () {
          $tdRow = $(this);
          var method = $th.hasClass('mdui-table-col-numeric') ? 'addClass' : 'removeClass';
          $tdRow.find('td').eq(i)[method]('mdui-table-col-numeric');
        });
      });
    };

    $(function () {
      // å®žä¾‹åŒ–è¡¨æ ¼
      $('.mdui-table').each(function () {
        var $table = $(this);
        if (!$table.data('mdui.table')) {
          $table.data('mdui.table', new Table($table));
        }
      });
    });

    /**
     * æ›´æ–°è¡¨æ ¼
     */
    mdui.updateTables = function () {
      $(arguments.length ? arguments[0] : '.mdui-table').each(function () {
        var $table = $(this);
        var inst = $table.data('mdui.table');

        if (inst) {
          inst.init();
        } else {
          $table.data('mdui.table', new Table($table));
        }
      });
    };

  })();


  /**
   * =============================================================================
   * ************   æ¶Ÿæ¼ª   ************
   * =============================================================================
   *
   * Inspired by https://github.com/nolimits4web/Framework7/blob/master/src/js/fast-clicks.js
   * https://github.com/nolimits4web/Framework7/blob/master/LICENSE
   *
   * Inspired by https://github.com/fians/Waves
   */

  (function () {

    var Ripple = {

      /**
       * 显示涟漪动画
       * @param e
       * @param $ripple
       */
      show: function (e, $ripple) {

        // é¼ æ ‡å³é”®ä¸äº§ç”Ÿæ¶Ÿæ¼ª
        if (e.button === 2) {
          return;
        }

        // ç‚¹å‡»ä½ç½®åæ ‡
        var tmp;
        if ('touches' in e && e.touches.length) {
          tmp = e.touches[0];
        } else {
          tmp = e;
        }

        var touchStartX = tmp.pageX;
        var touchStartY = tmp.pageY;

        // 涟漪位置
        var offset = $ripple.offset();
        var center = {
          x: touchStartX - offset.left,
          y: touchStartY - offset.top,
        };

        var height = $ripple.innerHeight();
        var width = $ripple.innerWidth();
        var diameter = Math.max(
          Math.pow((Math.pow(height, 2) + Math.pow(width, 2)), 0.5), 48
        );

        // 涟漪扩散动画
        var translate =
          'translate3d(' + (-center.x + width / 2) + 'px, ' + (-center.y + height / 2) + 'px, 0) ' +
          'scale(1)';

        // 涟漪的 DOM 结构
        $('<div class="mdui-ripple-wave" style="' +
          'width: ' + diameter + 'px; ' +
          'height: ' + diameter + 'px; ' +
          'margin-top:-' + diameter / 2 + 'px; ' +
          'margin-left:-' + diameter / 2 + 'px; ' +
          'left:' + center.x + 'px; ' +
          'top:' + center.y + 'px;">' +
          '</div>')

          // 缓存动画效果
          .data('translate', translate)

          .prependTo($ripple)
          .reflow()
          .transform(translate);
      },

      /**
       * 隐藏涟漪动画
       */
      hide: function () {
        var $ripple = $(this);

        $ripple.children('.mdui-ripple-wave').each(function () {
          removeRipple($(this));
        });

        $ripple.off('touchmove touchend touchcancel mousemove mouseup mouseleave', Ripple.hide);
      },
    };

    /**
     * 隐藏并移除涟漪
     * @param $wave
     */
    function removeRipple($wave) {
      if (!$wave.length || $wave.data('isRemoved')) {
        return;
      }

      $wave.data('isRemoved', true);

      var removeTimeout = setTimeout(function () {
        $wave.remove();
      }, 400);

      var translate = $wave.data('translate');

      $wave
        .addClass('mdui-ripple-wave-fill')
        .transform(translate.replace('scale(1)', 'scale(1.01)'))
        .transitionEnd(function () {
          clearTimeout(removeTimeout);

          $wave
            .addClass('mdui-ripple-wave-out')
            .transform(translate.replace('scale(1)', 'scale(1.01)'));

          removeTimeout = setTimeout(function () {
            $wave.remove();
          }, 700);

          setTimeout(function () {
            $wave.transitionEnd(function () {
              clearTimeout(removeTimeout);
              $wave.remove();
            });
          }, 0);
        });
    }

    /**
     * 显示涟漪,并绑定 touchend 等事件
     * @param e
     */
    function showRipple(e) {
      if (!TouchHandler.isAllow(e)) {
        return;
      }

      TouchHandler.register(e);

      var $ripple;
      var $target = $(e.target);

      // 获取含 .mdui-ripple 类的元ç´
      if ($target.hasClass('mdui-ripple')) {
        $ripple = $target;
      } else {
        $ripple = $target.parents('.mdui-ripple').eq(0);
      }

      if ($ripple.length) {

        // ç¦ç”¨çŠ¶æ€çš„å…ƒç´ ä¸Šä¸äº§ç”Ÿæ¶Ÿæ¼ªæ•ˆæžœ
        if ($ripple[0].disabled || $ripple.attr('disabled') !== null) {
          return;
        }

        Ripple.show(e, $ripple);

        $ripple.on('touchmove touchend touchcancel mousemove mouseup mouseleave', Ripple.hide);
      }
    }

    // 初始化绑定的事件
    $document
      .on(TouchHandler.start, showRipple)
      .on(TouchHandler.unlock, TouchHandler.register);
  })();


  /**
   * =============================================================================
   * ************   Text Field 文本框   ************
   * =============================================================================
   */

  (function () {

    var getProp = function (obj, prop) {
      return (
        typeof obj === 'object' &&
        obj !== null &&
        typeof obj[prop] !== 'undefined' &&
        obj[prop]
      ) ? obj[prop] : false;
    };

    /**
     * 输入框事件
     * @param e
     */
    var inputEvent = function (e) {
      var input = e.target;
      var $input = $(input);
      var event = e.type;
      var value = $input.val();

      // reInit 为 true 时,需要重新初始化文本框
      var reInit = getProp(e.detail, 'reInit');

      // domLoadedEvent 为 true 时,为 DOM åŠ è½½å®Œæ¯•åŽè‡ªåŠ¨è§¦å‘çš„äº‹ä»¶
      var domLoadedEvent = getProp(e.detail, 'domLoadedEvent');

      // 文本框类型
      var type = $input.attr('type') || '';
      if (['checkbox', 'button', 'submit', 'range', 'radio', 'image'].indexOf(type) >= 0) {
        return;
      }

      var $textField = $input.parent('.mdui-textfield');

      // 输入框是否聚焦
      if (event === 'focus') {
        $textField.addClass('mdui-textfield-focus');
      }

      if (event === 'blur') {
        $textField.removeClass('mdui-textfield-focus');
      }

      // 输入框是否为空
      if (event === 'blur' || event === 'input') {
        $textField[(value && value !== '') ? 'addClass' : 'removeClass']('mdui-textfield-not-empty');
      }

      // 输入框是否禁用
      $textField[input.disabled ? 'addClass' : 'removeClass']('mdui-textfield-disabled');

      // 表单验证
      if ((event === 'input' || event === 'blur') && !domLoadedEvent) {
        if (input.validity) {
          $textField[input.validity.valid ? 'removeClass' : 'addClass']('mdui-textfield-invalid');
        }
      }

      // textarea 高度自动调整
      if (e.target.nodeName.toLowerCase() === 'textarea') {
        $input.height('');
        var height = input.offsetHeight;
        var diff = height - input.clientHeight;
        var scrollHeight = input.scrollHeight;

        if (scrollHeight + diff > height) {
          var newAreaHeight = scrollHeight + diff;
          $input.height(newAreaHeight);
        }
      }

      // 实时字数统计
      if (reInit) {
        $textField
          .removeClass('mdui-textfield-has-counter')
          .find('.mdui-textfield-counter')
          .remove();
      }

      var maxlength = $input.attr('maxlength');
      if (maxlength) {
        if (reInit || domLoadedEvent) {
          $('<div class="mdui-textfield-counter">' +
              '<span class="mdui-textfield-counter-inputed"></span> / ' + maxlength +
            '</div>').appendTo($textField);

          // 如果没有 .mdui-textfield-error ä½œä¸ºå ä½ï¼Œéœ€è¦å¢žåŠ  .mdui-textfield 的下边距,
          // 使 .mdui-textfield-counter 不会覆盖在文本框上
          if (!$textField.find('.mdui-textfield-error').length) {
            $textField.addClass('mdui-textfield-has-counter');
          }
        }

        // 字符长度,确保统计方式和 maxlength 一致
        var inputed = value.length + value.split('\n').length - 1;
        $textField.find('.mdui-textfield-counter-inputed').text(inputed.toString());
      }

    };

    // 绑定事件
    $document.on('input focus blur', '.mdui-textfield-input', { useCapture: true }, inputEvent);

    // 可展开文本框展开
    $document.on('click', '.mdui-textfield-expandable .mdui-textfield-icon', function () {
      $(this)

        // 展开文本框
        .parents('.mdui-textfield')
        .addClass('mdui-textfield-expanded')

        // 聚焦到输入框
        .find('.mdui-textfield-input')[0].focus();
    });

    // 可展开文本框关闭
    $document.on('click', '.mdui-textfield-expanded .mdui-textfield-close', function () {
      $(this)

        // 关闭文本框
        .parents('.mdui-textfield')
        .removeClass('mdui-textfield-expanded')

        // 清空输入框
        .find('.mdui-textfield-input')
        .val('');
    });

    /**
     * 通过 JS 更新了表单内容,需要重新进行表单处理
     * @param- å¦‚æžœä¼ å…¥äº† .mdui-textfield 所在的 DOM å…ƒç´ ï¼Œåˆ™æ›´æ–°è¯¥æ–‡æœ¬æ¡†ï¼›å¦åˆ™ï¼Œæ›´æ–°æ‰€æœ‰æ–‡æœ¬æ¡†
     */
    mdui.updateTextFields = function () {
      $(arguments.length ? arguments[0] : '.mdui-textfield').each(function () {
        $(this)
          .find('.mdui-textfield-input')
          .trigger('input', {
            reInit: true,
          });
      });
    };

    $(function () {
      // DOM åŠ è½½å®ŒåŽè‡ªåŠ¨æ‰§è¡Œ
      $('.mdui-textfield-input').each(function () {
        $(this).trigger('input', {
          domLoadedEvent: true,
        });
      });
    });

  })();


  /**
   * =============================================================================
   * ************   Slider 滑块   ************
   * =============================================================================
   */

  (function () {

    /**
     * æ»‘å—çš„å€¼å˜æ›´åŽä¿®æ”¹æ»‘å—æ ·å¼
     * @param $slider
     */
    var updateValueStyle = function ($slider) {
      var data = $slider.data();

      var $track = data.$track;
      var $fill = data.$fill;
      var $thumb = data.$thumb;
      var $input = data.$input;
      var min = data.min;
      var max = data.max;
      var isDisabled = data.disabled;
      var isDiscrete = data.discrete;
      var $thumbText = data.$thumbText;
      var value = $input.val();
      var percent = (value - min) / (max - min) * 100;

      $fill.width(percent + '%');
      $track.width((100 - percent) + '%');

      if (isDisabled) {
        $fill.css('padding-right', '6px');
        $track.css('padding-left', '6px');
      }

      $thumb.css('left', percent + '%');

      if (isDiscrete) {
        $thumbText.text(value);
      }

      $slider[parseFloat(percent) === 0 ? 'addClass' : 'removeClass']('mdui-slider-zero');
    };

    /**
     * 重新初始化
     * @param $slider
     */
    var reInit = function ($slider) {
      var $track = $('<div class="mdui-slider-track"></div>');
      var $fill = $('<div class="mdui-slider-fill"></div>');
      var $thumb = $('<div class="mdui-slider-thumb"></div>');
      var $input = $slider.find('input[type="range"]');

      // 禁用状态
      var isDisabled = $input[0].disabled;
      $slider[isDisabled ? 'addClass' : 'removeClass']('mdui-slider-disabled');

      // 重新填充 HTML
      $slider.find('.mdui-slider-track').remove();
      $slider.find('.mdui-slider-fill').remove();
      $slider.find('.mdui-slider-thumb').remove();
      $slider.append($track).append($fill).append($thumb);

      // 间续型滑块
      var isDiscrete = $slider.hasClass('mdui-slider-discrete');

      var $thumbText;
      if (isDiscrete) {
        $thumbText = $('<span></span>');
        $thumb.empty().append($thumbText);
      }

      $slider.data({
        $track: $track,
        $fill: $fill,
        $thumb: $thumb,
        $input: $input,
        min: $input.attr('min'),    // 滑块最小值
        max: $input.attr('max'),    // 滑块最大值
        disabled: isDisabled,   nbsp;    // 是否禁用状态
        discrete: isDiscrete,       // 是否是间续型滑块
        $thumbText: $thumbText,      // 间续型滑块的数值
      });

      // 设置默认值
      updateValueStyle($slider);
    };

    var rangeSelector = '.mdui-slider input[type="range"]';

    $document

      // 滑动滑块事件
      .on('input change', rangeSelector, function () {
        var $slider = $(this).parent();
        updateValueStyle($slider);
      })

      // 开始触摸滑块事件
      .on(TouchHandler.start, rangeSelector, function (e) {
        if (!TouchHandler.isAllow(e)) {
          return;
        }

        TouchHandler.register(e);

        if (!this.disabled) {
          var $slider = $(this).parent();
          $slider.addClass('mdui-slider-focus');
        }
      })

      // 结束触摸滑块事件
      .on(TouchHandler.end, rangeSelector, function (e) {
        if (!TouchHandler.isAllow(e)) {
          return;
        }

        if (!this.disabled) {
          var $slider = $(this).parent();
          $slider.removeClass('mdui-slider-focus');
        }
      })

      .on(TouchHandler.unlock, rangeSelector, TouchHandler.register);

    /**
     * é¡µé¢åŠ è½½å®ŒåŽè‡ªåŠ¨åˆå§‹åŒ–
     */
    $(function () {
      $('.mdui-slider').each(function () {
        reInit($(this));
      });
    });

    /**
     * 重新初始化滑块
     */
    mdui.updateSliders = function () {
      $(arguments.length ? arguments[0] : '.mdui-slider').each(function () {
        reInit($(this));
      });
    };
  })();


  /**
   * =============================================================================
   * ************   Fab 浮动操作按钮   ************
   * =============================================================================
   */

  mdui.Fab = (function () {

    /**
     * 默认参数
     * @type {{}}
     */
    var DEFAULT = {
      trigger: 'hover',      // 触发方式 ['hover', 'click']
    };

    /**
     * 浮动操作按钮实例
     * @param selector 选择器或 HTML 字符串或 DOM å…ƒç´ æˆ– JQ 对象
     * @param opts
     * @constructor
     */
    function Fab(selector, opts) {
      var _this = this;

      _this.$fab = $(selector).eq(0);
      if (!_this.$fab.length) {
        return;
      }

      // 已通过 data 属性实例化过,不再重复实例化
      var oldInst = _this.$fab.data('mdui.fab');
      if (oldInst) {
        return oldInst;
      }

      _this.options = $.extend({}, DEFAULT, (opts || {}));
      _this.state = 'closed';

      _this.$btn = _this.$fab.find('.mdui-fab');
      _this.$dial = _this.$fab.find('.mdui-fab-dial');
      _this.$dialBtns = _this.$dial.find('.mdui-fab');

      if (_this.options.trigger === 'hover') {
        _this.$btn
          .on('touchstart mouseenter', function () {
            _this.open();
          });

        _this.$fab
          .on('mouseleave', function () {
            _this.close();
          });
      }

      if (_this.options.trigger === 'click') {
        _this.$btn
          .on(TouchHandler.start, function () {
            _this.open();
          });
      }

      // 触摸屏幕其他地方关闭快速拨号
      $document.on(TouchHandler.start, function (e) {
        if (!$(e.target).parents('.mdui-fab-wrapper').length) {
          _this.close();
        }
      });
    }

    /**
     * 打开菜单
     */
    Fab.prototype.open = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        return;
      }

      // ä¸ºèœå•ä¸­çš„æŒ‰é’®æ·»åŠ ä¸åŒçš„ transition-delay
      _this.$dialBtns.each(function (index, btn) {
        btn.style['transition-delay'] = btn.style['-webkit-transition-delay'] =
          15 * (_this.$dialBtns.length - index) + 'ms';
      });

      _this.$dial.addClass('mdui-fab-dial-show');

      // 如果按钮中存在 .mdui-fab-opened çš„å›¾æ ‡ï¼Œåˆ™è¿›è¡Œå›¾æ ‡åˆ‡æ¢
      if (_this.$btn.find('.mdui-fab-opened').length) {
        _this.$btn.addClass('mdui-fab-opened');
      }

      _this.state = 'opening';
      componentEvent('open', 'fab', _this, _this.$fab);

      // 打开顺序为从下到上逐个打开,最上面的打开后才表示动画完成
      _this.$dialBtns.eq(0).transitionEnd(function () {
        if (_this.$btn.hasClass('mdui-fab-opened')) {
          _this.state = 'opened';
          componentEvent('opened', 'fab', _this, _this.$fab);
        }
      });
    };

    /**
     * 关闭菜单
     */
    Fab.prototype.close = function () {
      var _this = this;

      if (_this.state === 'closing' || _this.state === 'closed') {
        return;
      }

      // ä¸ºèœå•ä¸­çš„æŒ‰é’®æ·»åŠ ä¸åŒçš„ transition-delay
      _this.$dialBtns.each(function (index, btn) {
        btn.style['transition-delay'] = btn.style['-webkit-transition-delay'] = 15 * index + 'ms';
      });

      _this.$dial.removeClass('mdui-fab-dial-show');
      _this.$btn.removeClass('mdui-fab-opened');
      _this.state = 'closing';
      componentEvent('close', 'fab', _this, _this.$fab);

      // 从上往下依次关闭,最后一个关闭后才表示动画完成
      _this.$dialBtns.eq(-1).transitionEnd(function () {
        if (!_this.$btn.hasClass('mdui-fab-opened')) {
          _this.state = 'closed';
          componentEvent('closed', 'fab', _this, _this.$fab);
        }
      });
    };

    /**
     * 切换菜单的打开状态
     */
    Fab.prototype.toggle = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        _this.close();
      } else if (_this.state === 'closing' || _this.state === 'closed') {
        _this.open();
      }
    };

    /**
     * 获取当前菜单状态
     * @returns {'opening'|'opened'|'closing'|'closed'}
     */
    Fab.prototype.getState = function () {
      return this.state;
    };

    /**
     * 以动画的形式显示浮动操作按钮
     */
    Fab.prototype.show = function () {
      this.$fab.removeClass('mdui-fab-hide');
    };

    /**
     * 以动画的形式隐藏浮动操作按钮
     */
    Fab.prototype.hide = function () {
      this.$fab.addClass('mdui-fab-hide');
    };

    return Fab;
  })();


  /**
   * =============================================================================
   * ************   Fab DATA API   ************
   * =============================================================================
   */

  $(function () {
    // mouseenter ä¸å†’æ³¡ï¼Œæ— æ³•è¿›è¡Œäº‹ä»¶å§”æ‰˜ï¼Œè¿™é‡Œç”¨ mouseover 代替。
    // 不管是 click 、 mouseover 还是 touchstart ,都先初始化。

    $document.on('touchstart mousedown mouseover', '[mdui-fab]', function (e) {
      var $this = $(this);

      var inst = $this.data('mdui.fab');
      if (!inst) {
        var options = parseOptions($this.attr('mdui-fab'));
        inst = new mdui.Fab($this, options);
        $this.data('mdui.fab', inst);
      }
    });
  });


  /**
   * =============================================================================
   * ************   Appbar   ************
   * =============================================================================
   * æ»šåŠ¨æ—¶è‡ªåŠ¨éšè—åº”ç”¨æ 
   * mdui-appbar-scroll-hide
   * mdui-appbar-scroll-toolbar-hide
   */

  $(function () {
    // æ»šåŠ¨æ—¶éšè—åº”ç”¨æ 
    $('.mdui-appbar-scroll-hide').each(function () {
      var $this = $(this);
      $this.data('mdui.headroom', new mdui.Headroom($this));
    });

    // æ»šåŠ¨æ—¶åªéšè—åº”ç”¨æ ä¸­çš„å·¥å…·æ 
    $('.mdui-appbar-scroll-toolbar-hide').each(function () {
      var $this = $(this);
      var inst = new mdui.Headroom($this, {
        pinnedClass: 'mdui-headroom-pinned-toolbar',
        unpinnedClass: 'mdui-headroom-unpinned-toolbar',
      });
      $this.data('mdui.headroom', inst);
    });
  });


  /**
   * =============================================================================
   * ************   Tab   ************
   * =============================================================================
   */

  mdui.Tab = (function () {

    var DEFAULT = {
      trigger: 'click',       // 触发方式 click: é¼ æ ‡ç‚¹å‡»åˆ‡æ¢ hover: é¼ æ ‡æ‚¬æµ®åˆ‡æ¢
      //animation: false,       // 切换时是否显示动画
      loop: false,            // 为true时,在最后一个选项卡时调用 next() 方法会回到第一个选项卡
    };

    // å…ƒç´ æ˜¯å¦å·²ç¦ç”¨
    var isDisabled = function ($ele) {
      return $ele[0].disabled || $ele.attr('disabled') !== null;
    };

    /**
     * 选项卡
     * @param selector
     * @param opts
     * @returns {*}
     * @constructor
     */
    function Tab(selector, opts) {
      var _this = this;

      _this.$tab = $(selector).eq(0);
      if (!_this.$tab.length) {
        return;
      }

      // 已通过自定义属性实例化过,不再重复实例化
      var oldInst = _this.$tab.data('mdui.tab');
      if (oldInst) {
        return oldInst;
      }

      _this.options = $.extend({}, DEFAULT, (opts || {}));
      _this.$tabs = _this.$tab.children('a');
      _this.$indicator = $('<div class="mdui-tab-indicator"></div>').appendTo(_this.$tab);
      _this.activeIndex = false;

      // æ ¹æ® url hash 获取默认激活的选项卡
      var hash = location.hash;
      if (hash) {
        _this.$tabs.each(function (i, tab) {
          if ($(tab).attr('href') === hash) {
            _this.activeIndex = i;
            return false;
          }
        });
      }

      // 含 mdui-tab-active çš„å…ƒç´ é»˜è®¤æ¿€æ´»
      if (_this.activeIndex === false) {
        _this.$tabs.each(function (i, tab) {
          if ($(tab).hasClass('mdui-tab-active')) {
            _this.activeIndex = i;
            return false;
          }
        });
      }

      // 默认激活第一个选项卡
      if (_this.activeIndex === false) {
        _this.activeIndex = 0;
      }

      // 设置激活状态选项卡
      _this._setActive();

      // 监听窗口大小变化事件,调整指示器位置
      $window.on('resize', $.throttle(function () {
        _this._setIndicatorPosition();
      }, 100));

      // 监听点击选项卡事件
      _this.$tabs.each(function (i, tab) {
        var $tab = $(tab);

        // ç‚¹å‡»æˆ–é¼ æ ‡ç§»å…¥è§¦å‘çš„äº‹ä»¶
        var clickEvent = function (e) {
          // ç¦ç”¨çŠ¶æ€çš„é€‰é¡¹æ— æ³•é€‰ä¸­
          if (isDisabled($tab)) {
            e.preventDefault();
            return;
          }

          _this.activeIndex = i;
          _this._setActive();
        };

        // æ— è®º trigger 是 click 还是 hover,都会响应 click 事件
        $tab.on('click', clickEvent);

        // trigger 为 hover 时,额外响应 mouseenter 事件
        if (_this.options.trigger === 'hover') {
          $tab.on('mouseenter', clickEvent);
        }

        $tab.on('click', function (e) {
          // 阻止链接的默认点击动作
          if ($tab.attr('href').indexOf('#') === 0) {
            e.preventDefault();
          }
        });
      });
    }

    /**
     * 设置激活状态的选项卡
     */
    Tab.prototype._setActive = function () {
      var _this = this;

      _this.$tabs.each(function (i, tab) {
        var $tab = $(tab);
        var targetId = $tab.attr('href');

        // 设置选项卡激活状态
        if (i === _this.activeIndex && !isDisabled($tab)) {
          if (!$tab.hasClass('mdui-tab-active')) {
            componentEvent('change', 'tab', _this, _this.$tab, {
              index: _this.activeIndex,
              target: tab,
            });
            componentEvent('show', 'tab', _this, $tab);

            $tab.addClass('mdui-tab-active');
          }

          $(targetId).show();
          _this._setIndicatorPosition();
        } else {
          $tab.removeClass('mdui-tab-active');
          $(targetId).hide();
        }
      });
    };

    /**
     * 设置选项卡指示器的位置
     */
    Tab.prototype._setIndicatorPosition = function () {
      var _this = this;

      var $activeTab = _this.$tabs.eq(_this.activeIndex);
      if (isDisabled($activeTab)) {
        return;
      }

      var activeTabOffset = $activeTab.offset();
      _this.$indicator.css({
        left: activeTabOffset.left + _this.$tab[0].scrollLeft -
              _this.$tab[0].getBoundingClientRect().left + 'px',
        width: $activeTab.width() + 'px',
      });
    };

    /**
     * 切换到下一个选项卡
     */
    Tab.prototype.next = function () {
      var _this = this;

      if (_this.$tabs.length > _this.activeIndex + 1) {
        _this.activeIndex++;
      } else if (_this.options.loop) {
        _this.activeIndex = 0;
      }

      _this._setActive();
    };

    /**
     * 切换到上一个选项卡
     */
    Tab.prototype.prev = function () {
      var _this = this;

      if (_this.activeIndex > 0) {
        _this.activeIndex--;
      } else if (_this.options.loop) {
        _this.activeIndex = _this.$tabs.length - 1;
      }

      _this._setActive();
    };

    /**
     * 显示指定序号或指定id的选项卡
     * @param index 从0开始的序号,或以#开头的id
     */
    Tab.prototype.show = function (index) {
      var _this = this;

      if (parseInt(index) === index) {
        _this.activeIndex = index;
      } else {
        _this.$tabs.each(function (i, tab) {
          if (tab.id === index) {
            _this.activeIndex = i;
            return false;
          }
        });
      }

      _this._setActive();
    };

    /**
     * åœ¨çˆ¶å…ƒç´ çš„å®½åº¦å˜åŒ–æ—¶ï¼Œéœ€è¦è°ƒç”¨è¯¥æ–¹æ³•é‡æ–°è°ƒæ•´æŒ‡ç¤ºå™¨ä½ç½®
     */
    Tab.prototype.handleUpdate = function () {
      this._setIndicatorPosition();
    };

    return Tab;
  })();


  /**
   * =============================================================================
   * ************   Tab 自定义属性 API   ************
   * =============================================================================
   */

  $(function () {
    $('[mdui-tab]').each(function () {
      var $this = $(this);
      var inst = $this.data('mdui.tab');
      if (!inst) {
        inst = new mdui.Tab($this, parseOptions($this.attr('mdui-tab')));
        $this.data('mdui.tab', inst);
      }
    });
  });


  /**
   * =============================================================================
   * ************   Drawer æŠ½å±‰æ    ************
   * =============================================================================
   *
   * åœ¨æ¡Œé¢è®¾å¤‡ä¸Šé»˜è®¤æ˜¾ç¤ºæŠ½å±‰æ ï¼Œä¸æ˜¾ç¤ºé®ç½©å±‚
   * åœ¨æ‰‹æœºå’Œå¹³æ¿è®¾å¤‡ä¸Šé»˜è®¤ä¸æ˜¾ç¤ºæŠ½å±‰æ ï¼Œå§‹ç»ˆæ˜¾ç¤ºé®ç½©å±‚ï¼Œä¸”è¦†ç›–å¯¼èˆªæ 
   */

  mdui.Drawer = (function () {

    /**
     * 默认参数
     * @type {{}}
     */
    var DEFAULT = {
      // 在桌面设备上是否显示遮罩层。手机和平板不受这个参数影响,始终会显示遮罩层
      overlay: false,
    };

    var isDesktop = function () {
      return $window.width() >= 1024;
    };

    /**
     * æŠ½å±‰æ å®žä¾‹
     * @param selector 选择器或 HTML 字符串或 DOM å…ƒç´
     * @param opts
     * @constructor
     */
    function Drawer(selector, opts) {
      var _this = this;

      _this.$drawer = $(selector).eq(0);
      if (!_this.$drawer.length) {
        return;
      }

      var oldInst = _this.$drawer.data('mdui.drawer');
      if (oldInst) {
        return oldInst;
      }

      _this.options = $.extend({}, DEFAULT, (opts || {}));

      _this.overlay = false; // 是否显示着遮罩层
      _this.position = _this.$drawer.hasClass('mdui-drawer-right') ? 'right' : 'left';

      if (_this.$drawer.hasClass('mdui-drawer-close')) {
        _this.state = 'closed';
      } else if (_this.$drawer.hasClass('mdui-drawer-open')) {
        _this.state = 'opened';
      } else if (isDesktop()) {
        _this.state = 'opened';
      } else {
        _this.state = 'closed';
      }

      // 浏览器窗口大小调整时
      $window.on('resize', $.throttle(function () {
        // 由手机平板切换到桌面时
        if (isDesktop()) {
          // 如果显示着遮罩,则隐藏遮罩
          if (_this.overlay && !_this.options.overlay) {
            $.hideOverlay();
            _this.overlay = false;
            $.unlockScreen();
          }

          // 没有强制关闭,则状态为打开状态
          if (!_this.$drawer.hasClass('mdui-drawer-close')) {
            _this.state = 'opened';
          }
        }

        // ç”±æ¡Œé¢åˆ‡æ¢åˆ°æ‰‹æœºå¹³æ¿æ—¶ã€‚å¦‚æžœæŠ½å±‰æ æ˜¯æ‰“å¼€ç€çš„ä¸”æ²¡æœ‰é®ç½©å±‚ï¼Œåˆ™å…³é—­æŠ½å±‰æ 
        else {
          if (!_this.overlay && _this.state === 'opened') {
            // æŠ½å±‰æ å¤„äºŽå¼ºåˆ¶æ‰“å¼€çŠ¶æ€ï¼Œæ·»åŠ é®ç½©
            if (_this.$drawer.hasClass('mdui-drawer-open')) {
              $.showOverlay();
              _this.overlay = true;
              $.lockScreen();

              $('.mdui-overlay').one('click', function () {
                _this.close();
              });
            } else {
              _this.state = 'closed';
            }
          }
        }
      }, 100));

      // 绑定关闭按钮事件
      _this.$drawer.find('[mdui-drawer-close]').each(function () {
        $(this).on('click', function () {
          _this.close();
        });
      });
    }

    /**
     * 动画结束回调
     * @param inst
     */
    var transitionEnd = function (inst) {
      if (inst.$drawer.hasClass('mdui-drawer-open')) {
        inst.state = 'opened';
        componentEvent('opened', 'drawer', inst, inst.$drawer);
      } else {
        inst.state = 'closed';
        componentEvent('closed', 'drawer', inst, inst.$drawer);
      }
    };

    /**
     * æ‰“å¼€æŠ½å±‰æ 
     */
    Drawer.prototype.open = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        return;
      }

      _this.state = 'opening';
      componentEvent('open', 'drawer', _this, _this.$drawer);

      if (!_this.options.overlay) {
        $body.addClass('mdui-drawer-body-' + _this.position);
      }

      _this.$drawer
        .removeClass('mdui-drawer-close')
        .addClass('mdui-drawer-open')
        .transitionEnd(function () {
          transitionEnd(_this);
        });

      if (!isDesktop() || _this.options.overlay) {
        _this.overlay = true;
        $.showOverlay().one('click', function () {
          _this.close();
        });

        $.lockScreen();
      }
    };

    /**
     * å…³é—­æŠ½å±‰æ 
     */
    Drawer.prototype.close = function () {
      var _this = this;

      if (_this.state === 'closing' || _this.state === 'closed') {
        return;
      }

      _this.state = 'closing';
      componentEvent('close', 'drawer', _this, _this.$drawer);

      if (!_this.options.overlay) {
        $body.removeClass('mdui-drawer-body-' + _this.position);
      }

      _this.$drawer
        .addClass('mdui-drawer-close')
        .removeClass('mdui-drawer-open')
        .transitionEnd(function () {
          transitionEnd(_this);
        });

      if (_this.overlay) {
        $.hideOverlay();
        _this.overlay = false;
        $.unlockScreen();
      }
    };

    /**
     * åˆ‡æ¢æŠ½å±‰æ æ‰“å¼€/关闭状态
     */
    Drawer.prototype.toggle = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        _this.close();
      } else if (_this.state === 'closing' || _this.state === 'closed') {
        _this.open();
      }
    };

    /**
     * èŽ·å–æŠ½å±‰æ çŠ¶æ€
     * @returns {'opening'|'opened'|'closing'|'closed'}
     */
    Drawer.prototype.getState = function () {
      return this.state;
    };

    return Drawer;

  })();


  /**
   * =============================================================================
   * ************   Drawer 自定义属性 API   ************
   * =============================================================================
   */

  $(function () {
    $('[mdui-drawer]').each(function () {
      var $this = $(this);
      var options = parseOptions($this.attr('mdui-drawer'));
      var selector = options.target;
      delete options.target;

      var $drawer = $(selector).eq(0);

      var inst = $drawer.data('mdui.drawer');
      if (!inst) {
        inst = new mdui.Drawer($drawer, options);
        $drawer.data('mdui.drawer', inst);
      }

      $this.on('click', function () {
        inst.toggle();
      });
    });
  });


  /**
   * =============================================================================
   * ************   Dialog 对话框   ************
   * =============================================================================
   */

  mdui.Dialog = (function () {

    /**
     * 默认参数
     */
    var DEFAULT = {
      history: true,                // 监听 hashchange 事件
      overlay: true,                // 打开对话框时是否显示遮罩
      modal: false,                 // 是否模态化对话框,为 false 时点击对话框外面区域关闭对话框,为 true 时不关闭
      closeOnEsc: true,             // 按下 esc 关闭对话框
      closeOnCancel: true,          // 按下取消按钮时关闭对话框
      closeOnConfirm: true,         // 按下确认按钮时关闭对话框
      destroyOnClosed: false,        // 关闭后销毁
    };

    /**
     * 遮罩层元ç´
     */
    var $overlay;

    /**
     * 窗口是否已锁定
     */
    var isLockScreen;

    /**
     * 当前对话框实例
     */
    var currentInst;

    /**
     * 队列名
     * @type {string}
     */
    var queueName = '__md_dialog';

    /**
     * 窗口宽度变化,或对话框内容变化时,调整对话框位置和对话框内的滚动条
     */
    var readjust = function () {
      if (!currentInst) {
        return;
      }

      var $dialog = currentInst.$dialog;

      var $dialogTitle = $dialog.children('.mdui-dialog-title');
      var $dialogContent = $dialog.children('.mdui-dialog-content');
      var $dialogActions = $dialog.children('.mdui-dialog-actions');

      // 调整 dialog çš„ top å’Œ height 值
      $dialog.height('');
      $dialogContent.height('');

      var dialogHeight = $dialog.height();
      $dialog.css({
        top: (($window.height() - dialogHeight) / 2) + 'px',
        height: dialogHeight + 'px',
      });

      // 调整 mdui-dialog-content 的高度
      $dialogContent.height(
        dialogHeight -
        ($dialogTitle.height() || 0) -
        ($dialogActions.height() || 0)
      );
    };

    /**
     * hashchange 事件触发时关闭对话框
     */
    var hashchangeEvent = function () {
      if (location.hash.substring(1).indexOf('&mdui-dialog') < 0) {
        currentInst.close(true);
      }
    };

    /**
     * 点击遮罩层关闭对话框
     * @param e
     */
    var overlayClick = function (e) {
      if ($(e.target).hasClass('mdui-overlay')) {
        currentInst.close();
      }
    };

    /**
     * 对话框实例
     * @param selector 选择器或 HTML 字符串或 DOM å…ƒç´
     * @param opts
     * @constructor
     */
    function Dialog(selector, opts) {
      var _this = this;

      // 对话框元ç´
      _this.$dialog = $(selector).eq(0);
      if (!_this.$dialog.length) {
        return;
      }

      // 已通过 data 属性实例化过,不再重复实例化
      var oldInst = _this.$dialog.data('mdui.dialog');
      if (oldInst) {
        return oldInst;
      }

      // å¦‚æžœå¯¹è¯æ¡†å…ƒç´ æ²¡æœ‰åœ¨å½“å‰æ–‡æ¡£ä¸­ï¼Œåˆ™éœ€è¦æ·»åŠ
      if (!$.contains($body[0], _this.$dialog[0])) {
        _this.append = true;
        $body.append(_this.$dialog);
      }

      _this.options = $.extend({}, DEFAULT, (opts || {}));
      _this.state = 'closed';

      // 绑定取消按钮事件
      _this.$dialog.find('[mdui-dialog-cancel]').each(function () {
        $(this).on('click', function () {
          componentEvent('cancel', 'dialog', _this, _this.$dialog);
          if (_this.options.closeOnCancel) {
            _this.close();
          }
        });
      });

      // 绑定确认按钮事件
      _this.$dialog.find('[mdui-dialog-confirm]').each(function () {
        $(this).on('click', function () {
          componentEvent('confirm', 'dialog', _this, _this.$dialog);
          if (_this.options.closeOnConfirm) {
            _this.close();
          }
        });
      });

      // 绑定关闭按钮事件
      _this.$dialog.find('[mdui-dialog-close]').each(function () {
        $(this).on('click', function () {
          _this.close();
        });
      });
    }

    /**
     * 打开指定对话框
     * @private
     */
    Dialog.prototype._doOpen = function () {
      var _this = this;

      currentInst = _this;

      if (!isLockScreen) {
        $.lockScreen();
        isLockScreen = true;
      }

      _this.$dialog.show();

      readjust();
      $window.on('resize', $.throttle(function () {
        readjust();
      }, 100));

      // 打开消息框
      _this.state = 'opening';
      componentEvent('open', 'dialog', _this, _this.$dialog);

      _this.$dialog
        .addClass('mdui-dialog-open')
        .transitionEnd(function () {
          if (_this.$dialog.hasClass('mdui-dialog-open')) {
            _this.state = 'opened';
            componentEvent('opened', 'dialog', _this, _this.$dialog);
          } else {
            _this.state = 'closed';
            componentEvent('closed', 'dialog', _this, _this.$dialog);
          }
        });

      // ä¸å­˜åœ¨é®ç½©å±‚å…ƒç´ æ—¶ï¼Œæ·»åŠ é®ç½©å±‚
      if (!$overlay) {
        $overlay = $.showOverlay(5100);
      }

      $overlay

        // 点击遮罩层时是否关闭对话框
        [_this.options.modal ? 'off' : 'on']('click', overlayClick)

        // 是否显示遮罩层,不显示时,把遮罩层背景透明
        .css('opacity', _this.options.overlay ? '' : 0);

      if (_this.options.history) {
        // 如果 hash 中原来就有 &mdui-dialogï¼Œå…ˆåˆ é™¤ï¼Œé¿å…åŽé€€åŽ†å²çºªå½•åŽä»ç„¶æœ‰ &mdui-dialog å¯¼è‡´æ— æ³•å…³é—­
        var hash = location.hash.substring(1);
        if (hash.indexOf('&mdui-dialog') > -1) {
          hash = hash.replace(/&mdui-dialog/g, '');
        }

        // 后退按钮关闭对话框
        location.hash = hash + '&mdui-dialog';
        $window.on('hashchange', hashchangeEvent);
      }
    };

    /**
     * 打开对话框
     */
    Dialog.prototype.open = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        return;
      }

      // 如果当前有正在打开或已经打开的对话框,æˆ–é˜Ÿåˆ—ä¸ä¸ºç©ºï¼Œåˆ™å…ˆåŠ å…¥é˜Ÿåˆ—ï¼Œç­‰æ—§å¯¹è¯æ¡†å¼€å§‹å…³é—­æ—¶å†æ‰“å¼€
      if (
        (currentInst && (currentInst.state === 'opening' || currentInst.state === 'opened')) ||
        queue.queue(queueName).length
      ) {
        queue.queue(queueName, function () {
          _this._doOpen();
        });

        return;
      }

      _this._doOpen();
    };

    /**
     * 关闭对话框
     */
    Dialog.prototype.close = function () {
      var _this = this;

      if (_this.state === 'closing' || _this.state === 'closed') {
        return;
      }

      currentInst = null;

      _this.state = 'closing';
      componentEvent('close', 'dialog', _this, _this.$dialog);

      // 所有对话框都关闭,且当前没有打开的对话框时,隐藏遮罩
      if (queue.queue(queueName).length === 0 && $overlay) {
        $.hideOverlay();
        $overlay = null;
      }

      _this.$dialog
        .removeClass('mdui-dialog-open')
        .transitionEnd(function () {
          if (!_this.$dialog.hasClass('mdui-dialog-open')) {
            _this.state = 'closed';
            componentEvent('closed', 'dialog', _this, _this.$dialog);

            _this.$dialog.hide();

            // 所有对话框都关闭,且当前没有打开的对话框时,解锁屏幕
            if (queue.queue(queueName).length === 0 && !currentInst && isLockScreen) {
              $.unlockScreen();
              isLockScreen = false;
            }

            $window.off('resize', $.throttle(function () {
              readjust();
            }, 100));

            if (_this.options.destroyOnClosed) {
              _this.destroy();
            }
          } else {
            _this.state = 'opened';
            componentEvent('opened', 'dialog', _this, _this.$dialog);
          }
        });

      if (_this.options.history && queue.queue(queueName).length === 0) {
        // 是否需要后退历史纪录,默认为 false。
        // 为 false 时是通过 js 关闭,需要后退一个历史记录
        // 为 true 时是通过后退按钮关闭,不需要后退历史记录
        if (!arguments[0]) {
          window.history.back();
        }

        $window.off('hashchange', hashchangeEvent);
      }

      // 关闭旧对话框,打开新对话框。
      // åŠ ä¸€ç‚¹å»¶è¿Ÿï¼Œä»…ä»…ä¸ºäº†è§†è§‰æ•ˆæžœæ›´å¥½ã€‚ä¸åŠ å»¶æ—¶ä¹Ÿä¸å½±å“åŠŸèƒ½
      setTimeout(function () {
        queue.dequeue(queueName);
      }, 100);
    };

    /**
     * 切换对话框打开/关闭状态
     */
    Dialog.prototype.toggle = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        _this.close();
      } else if (_this.state === 'closing' || _this.state === 'closed') {
        _this.open();
      }
    };

    /**
     * 获取对话框状态
     * @returns {'opening'|'opened'|'closing'|'closed'}
     */
    Dialog.prototype.getState = function () {
      return this.state;
    };

    /**
     * 销毁对话框
     */
    Dialog.prototype.destroy = function () {
      var _this = this;

      if (_this.append) {
        _this.$dialog.remove();
      }

      _this.$dialog.removeData('mdui.dialog');

      if (queue.queue(queueName).length === 0 && !currentInst) {
        if ($overlay) {
          $.hideOverlay();
          $overlay = null;
        }

        if (isLockScreen) {
          $.unlockScreen();
          isLockScreen = false;
        }
      }
    };

    /**
     * 对话框内容变化时,需要调用该方法来调整对话框位置和滚动条高度
     */
    Dialog.prototype.handleUpdate = function () {
      readjust();
    };

    // esc 按下时关闭对话框
    $document.on('keydown', function (e) {
      if (
        currentInst &&
        currentInst.options.closeOnEsc &&
        currentInst.state === 'opened' &&
        e.keyCode === 27
      ) {
        currentInst.close();
      }
    });

    return Dialog;

  })();


  /**
   * =============================================================================
   * ************   Dialog DATA API   ************
   * =============================================================================
   */

  $(function () {
    $document.on('click', '[mdui-dialog]', function () {
      var $this = $(this);
      var options = parseOptions($this.attr('mdui-dialog'));
      var selector = options.target;
      delete options.target;

      var $dialog = $(selector).eq(0);

      var inst = $dialog.data('mdui.dialog');
      if (!inst) {
        inst = new mdui.Dialog($dialog, options);
        $dialog.data('mdui.dialog', inst);
      }

      inst.open();
    });
  });


  /**
   * =============================================================================
   * ************   mdui.dialog(options)   ************
   * =============================================================================
   */

  mdui.dialog = function (options) {

    /**
     * 默认参数
     */
    var DEFAULT = {
      title: '',                // æ ‡é¢˜
      content: '',              // 文本
      buttons: [],              // 按钮
      stackedButtons: false,    // 垂直排列按钮
      cssClass: '',             // 在 Dialog ä¸Šæ·»åŠ çš„ CSS ç±»
      history: true,            // 监听 hashchange 事件
      overlay: true,            // 是否显示遮罩
      modal: false,             // 是否模态化对话框
      closeOnEsc: true,         // 按下 esc 时关闭对话框
      destroyOnClosed: true,    // 关闭后销毁
      onOpen: function () {     // 打开动画开始时的回调
      },

      onOpened: function () {   // 打开动画结束后的回调
  &nbnbsp;   },

      onClose: function () {    // 关闭动画开始时的回调
      },

      onClosed: function () {   // 关闭动画结束时的回调
      },
    };

    /**
     * 按钮的默认参数
     */
    var DEFAULT_BUTTON = {
      text: '',                   // 按钮文本
      bold: false,                // æŒ‰é’®æ–‡æœ¬æ˜¯å¦åŠ ç²—
      close: true,                // 点击按钮后关闭对话框
      onClick: function (inst) {  // 点击按钮的回调
      },
    };

    // 合并参数
    options = $.extend({}, DEFAULT, (options || {}));
    $.each(options.buttons, function (i, button) {
      options.buttons[i] = $.extend({}, DEFAULT_BUTTON, button);
    });

    // 按钮的 HTML
    var buttonsHTML = '';
    if (options.buttons.length) {
      buttonsHTML =
        '<div class="mdui-dialog-actions ' +
          (options.stackedButtons ? 'mdui-dialog-actions-stacked' : '') +
        '">';
      $.each(options.buttons, function (i, button) {
        buttonsHTML +=
          '<a href="javascript:void(0)" ' +
            'class="mdui-btn mdui-ripple mdui-text-color-primary ' +
            (button.bold ? 'mdui-btn-bold' : '') + '">' +
            button.text +
          '</a>';
      });

      buttonsHTML += '</div>';
    }

    // Dialog çš„ HTML
    var HTML =
      '<div class="mdui-dialog ' + options.cssClass + '">' +
        (options.title ? '<div class="mdui-dialog-title">' + options.title + '</div>' : '') +
        (options.content ? '<div class="mdui-dialog-content">' + options.content + '</div>' : '') +
        buttonsHTML +
      '</div>';

    // 实例化 Dialog
    var inst = new mdui.Dialog(HTML, {
      history: options.history,
      overlay: options.overlay,
      modal: options.modal,
      closeOnEsc: options.closeOnEsc,
      destroyOnClosed: options.destroyOnClosed,
    });

    // 绑定按钮事件
    if (options.buttons.length) {
      inst.$dialog.find('.mdui-dialog-actions .mdui-btn').each(function (i, button) {
        $(button).on('click', function () {
          if (typeof options.buttons[i].onClick === 'function') {
            options.buttons[i].onClick(inst);
          }

          if (options.buttons[i].close) {
            inst.close();
          }
        });
      });
    }

    // 绑定打开关闭事件
    if (typeof options.onOpen === 'function') {
      inst.$dialog
        .on('open.mdui.dialog', function () {
          options.onOpen(inst);
        })
        .on('opened.mdui.dialog', function () {
          options.onOpened(inst);
        })
        .on('close.mdui.dialog', function () {
          options.onClose(inst);
        })
        .on('closed.mdui.dialog', function () {
          options.onClosed(inst);
        });
    }

    inst.open();

    return inst;
  };


  /**
   * =============================================================================
   * ************   mdui.alert(text, title, onConfirm, options)   ************
   * ************   mdui.alert(text, onConfirm, options)   ************
   * =============================================================================
   */

  mdui.alert = function (text, title, onConfirm, options) {

    // title 参数可选
    if (typeof title === 'function') {
      title = '';
      onConfirm = arguments[1];
      options = arguments[2];
    }

    if (onConfirm === undefined) {
      onConfirm = function () {};
    }

    if (options === undefined) {
      options = {};
    }

    /**
     * 默认参数
     */
    var DEFAULT = {
      confirmText: 'ok',             // 按钮上的文本
      history: true,                 // 监听 hashchange 事件
      modal: false,                  // 是否模态化对话框,为 false 时点击对话框外面区域关闭对话框,为 true 时不关闭
      closeOnEsc: true,              // 按下 esc 关闭对话框
    };

    options = $.extend({}, DEFAULT, options);

    return mdui.dialog({
      title: title,
      content: text,
      buttons: [
        {
          text: options.confirmText,
          bold: false,
          close: true,
          onClick: onConfirm,
        },
      ],
      cssClass: 'mdui-dialog-alert',
      history: options.history,
      modal: options.modal,
      closeOnEsc: options.closeOnEsc,
    });
  };


  /**
   * =============================================================================
   * ************   mdui.confirm(text, title, onConfirm, onCancel, options)   ************
   * ************   mdui.confirm(text, onConfirm, onCancel, options)          ************
   * =============================================================================
   */

  mdui.confirm = function (text, title, onConfirm, onCancel, options) {

    // title 参数可选
    if (typeof title === 'function') {
      title = '';
      onConfirm = arguments[1];
      onCancel = arguments[2];
      options = arguments[3];
    }

    if (onConfirm === undefined) {
      onConfirm = function () {};
    }

    if (onCancel === undefined) {
      onCancel = function () {};
    }

    if (options === undefined) {
      options = {};
    }

    /**
     * 默认参数
     */
    var DEFAULT = {
      confirmText: 'ok',            // 确认按钮的文本
      cancelText: 'cancel',         // 取消按钮的文本
      history: true,                // 监听 hashchange 事件
      modal: false,                 // 是否模态化对话框,为 false 时点击对话框外面区域关闭对话框,为 true 时不关闭
      closeOnEsc: true,             // 按下 esc 关闭对话框
    };

    options = $.extend({}, DEFAULT, options);

    return mdui.dialog({
      title: title,
      content: text,
      buttons: [
        {
          text: options.cancelText,
          bold: false,
          close: true,
          onClick: onCancel,
        },
        {
          text: options.confirmText,
          bold: false,
          close: true,
          onClick: onConfirm,
        },
      ],
      cssClass: 'mdui-dialog-confirm',
      history: options.history,
      modal: options.modal,
      closeOnEsc: options.closeOnEsc,
    });
  };


  /**
   * =============================================================================
   * ************   mdui.prompt(label, title, onConfirm, onCancel, options)   ************
   * ************   mdui.prompt(label, onConfirm, onCancel, options)          ************
   * =============================================================================
   */

  mdui.prompt = function (label, title, onConfirm, onCancel, options) {

    // title 参数可选
    if (typeof title === 'function') {
      title = '';
      onConfirm = arguments[1];
      onCancel = arguments[2];
      options = arguments[3];
    }

    if (onConfirm === undefined) {
      onConfirm = function () {};
    }

    if (onCancel === undefined) {
      onCancel = function () {};
    }

    if (options === undefined) {
      options = {};
    }

    /**
     * 默认参数
     */
    var DEFAULT = {
      confirmText: 'ok',        // 确认按钮的文本
      cancelText: 'cancel',     // 取消按钮的文本
      history: true,            // 监听 hashchange 事件
      modal: false,             // 是否模态化对话框,为 false 时点击对话框外面区域关闭对话框,为 true 时不关闭
      closeOnEsc: true,         // 按下 esc 关闭对话框
      type: 'text',             // 输入框类型,text: 单行文本框 textarea: 多行文本框
      maxlength: '',            // 最大输入字符数
      defaultValue: '',         // 输入框中的默认文本
    };

    options = $.extend({}, DEFAULT, options);

    var content =
      '<div class="mdui-textfield">' +
        (label ? '<label class="mdui-textfield-label">' + label + '</label>' : '') +
        (options.type === 'text' ?
          '<input class="mdui-textfield-input" type="text" ' +
            'value="' + options.defaultValue + '" ' +
            (options.maxlength ? ('maxlength="' + options.maxlength + '"') : '') + '/>' :
          '') +
        (options.type === 'textarea' ?
          '<textarea class="mdui-textfield-input" ' +
            (options.maxlength ? ('maxlength="' + options.maxlength + '"') : '') + '>' +
              options.defaultValue +
          '</textarea>' :
          '') +
      '</div>';

    return mdui.dialog({
      title: title,
      content: content,
      buttons: [
        {
          text: options.cancelText,
          bold: false,
          close: true,
          onClick: function (inst) {
            var value = inst.$dialog.find('.mdui-textfield-input').val();
            onCancel(value, inst);
          },
        },
        {
          text: options.confirmText,
          bold: false,
          close: true,
          onClick: function (inst) {
            var value = inst.$dialog.find('.mdui-textfield-input').val();
            onConfirm(value, inst);
          },
        },
      ],
      cssClass: 'mdui-dialog-prompt',
      history: options.history,
      modal: options.modal,
      closeOnEsc: options.closeOnEsc,
      onOpen: function (inst) {

        // 初始化输入框
        var $input = inst.$dialog.find('.mdui-textfield-input');
        mdui.updateTextFields($input);

        // 聚焦到输入框
        $input[0].focus();

        // 如果是多行输入框,监听输入框的 input 事件,更新对话框高度
        if (options.type === 'textarea') {
          $input.on('input', function () {
            inst.handleUpdate();
          });
        }

        // æœ‰å­—ç¬¦æ•°é™åˆ¶æ—¶ï¼ŒåŠ è½½å®Œæ–‡æœ¬æ¡†åŽ DOM 会变化,需要更新对话框高度
        if (options.maxlength) {
          inst.handleUpdate();
        }
      },
    });

  };


  /**
   * =============================================================================
   * ************   ToolTip 工具提示   ************
   * =============================================================================
   */

  mdui.Tooltip = (function () {

    /**
     * 默认参数
     */
    var DEFAULT = {
      position: 'auto',     // 提示所在位置
      delay: 0,             // 延迟,单位毫秒
      content: '',          // 提示文本,允许包含 HTML
    };

    /**
     * 是否是桌面设备
     * @returns {boolean}
     */
    var isDesktop = function () {
      return $window.width() > 1024;
    };

    /**
     * 设置 Tooltip 的位置
     * @param inst
     */
    function setPosition(inst) {
      var marginLeft;
      var marginTop;
      var position;

      // 触发的元ç´
      var targetProps = inst.$target[0].getBoundingClientRect();

      // è§¦å‘çš„å…ƒç´ å’Œ Tooltip 之间的距离
      var targetMargin = (isDesktop() ? 14 : 24);

      // Tooltip 的宽度和高度
      var tooltipWidth = inst.$tooltip[0].offsetWidth;
      var tooltipHeight = inst.$tooltip[0].offsetHeight;

      // Tooltip 的方向
      position = inst.options.position;

      // 自动判断位置,加 2px,使 Tooltip 距离窗口边框至少有 2px 的间距
      if (['bottom', 'top', 'left', 'right'].indexOf(position) === -1) {
        if (
          targetProps.top + targetProps.height + targetMargin + tooltipHeight + 2 <
          $window.height()
        ) {
          position = 'bottom';
        } else if (targetMargin + tooltipHeight + 2 < targetProps.top) {
          position = 'top';
        } else if (targetMargin + tooltipWidth + 2 < targetProps.left) {
          position = 'left';
        } else if (
          targetProps.width + targetMargin + tooltipWidth + 2 <
          $window.width() - targetProps.left
        ) {
          position = 'right';
        } else {
          position = 'bottom';
        }
      }

      // 设置位置
      switch (position) {
        case 'bottom':
          marginLeft = -1 * (tooltipWidth / 2);
          marginTop = (targetProps.height / 2) + targetMargin;
          inst.$tooltip.transformOrigin('top center');
          break;
        case 'top':
          marginLeft = -1 * (tooltipWidth / 2);
          marginTop = -1 * (tooltipHeight + (targetProps.height / 2) + targetMargin);
          inst.$tooltip.transformOrigin('bottom center');
          break;
        case 'left':
          marginLeft = -1 * (tooltipWidth + (targetProps.width / 2) + targetMargin);
          marginTop = -1 * (tooltipHeight / 2);
          inst.$tooltip.transformOrigin('center right');
          break;
        case 'right':
          marginLeft = (targetProps.width / 2) + targetMargin;
          marginTop = -1 * (tooltipHeight / 2);
          inst.$tooltip.transformOrigin('center left');
          break;
      }

      var targetOffset = inst.$target.offset();
      inst.$tooltip.css({
        top: targetOffset.top + (targetProps.height / 2) + 'px',
        left: targetOffset.left + (targetProps.width / 2) + 'px',
        'margin-left': marginLeft + 'px',
        'margin-top': marginTop + 'px',
      });
    }

    /**
     * Tooltip 实例
     * @param selector
     * @param opts
     * @constructor
     */
    function Tooltip(selector, opts) {
      var _this = this;

      _this.$target = $(selector).eq(0);
      if (!_this.$target.length) {
        return;
      }

      // 已通过 data 属性实例化过,不再重复实例化
      var oldInst = _this.$target.data('mdui.tooltip');
      if (oldInst) {
        return oldInst;
      }

      _this.options = $.extend({}, DEFAULT, (opts || {}));
      _this.state = 'closed';

      // 创建 Tooltip HTML
      var guid = $.guid('tooltip');
      _this.$tooltip = $(
        '<div class="mdui-tooltip" id="mdui-tooltip-' + guid + '">' +
          _this.options.content +
        '</div>'
      ).appendTo($body);

      // 绑定事件
      _this.$target
        .on('touchstart mouseenter', function (e) {
          if (!TouchHandler.isAllow(e)) {
            return;
          }

          TouchHandler.register(e);

          _this.open();
        })
        .on('touchend mouseleave', function (e) {
          if (!TouchHandler.isAllow(e)) {
            return;
          }

          _this.close();
        })
        .on(TouchHandler.unlock, TouchHandler.register);
    }

    /**
     * 动画结束回调
     * @private
     */
    var transitionEnd = function (inst) {
      if (inst.$tooltip.hasClass('mdui-tooltip-open')) {
        inst.state = 'opened';
        componentEvent('opened', 'tooltip', inst, inst.$target);
      } else {
        inst.state = 'closed';
        componentEvent('closed', 'tooltip', inst, inst.$target);
      }
    };

    /**
     * 执行打开 Tooltip
     * @private
     */
    Tooltip.prototype._doOpen = function () {
      var _this = this;

      _this.state = 'opening';
      componentEvent('open', 'tooltip', _this, _this.$target);

      _this.$tooltip
        .addClass('mdui-tooltip-open')
        .transitionEnd(function () {
          transitionEnd(_this);
        });
    };

    /**
     * 打开 Tooltip
     * @param opts 允许每次打开时设置不同的参数
     */
    Tooltip.prototype.open = function (opts) {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        return;
      }

      var oldOpts = _this.options;

      // 合并 data 属性参数
      $.extend(_this.options, parseOptions(_this.$target.attr('mdui-tooltip')));
      if (opts) {
        $.extend(_this.options, opts);
      }

      // tooltip 的内容有更新
      if (oldOpts.content !== _this.options.content) {
        _this.$tooltip.html(_this.options.content);
      }

      setPosition(_this);

      if (_this.options.delay) {
        _this.timeoutId = setTimeout(function () {
          _this._doOpen();
        }, _this.options.delay);
      } else {
        _this.timeoutId = false;
        _this._doOpen();
      }
    };

    /**
     * 关闭 Tooltip
     */
    Tooltip.prototype.close = function () {
      var _this = this;

      if (_this.timeoutId) {
        clearTimeout(_this.timeoutId);
        _this.timeoutId = false;
      }

      if (_this.state === 'closing' || _this.state === 'closed') {
        return;
      }

      _this.state = 'closing';
      componentEvent('close', 'tooltip', _this, _this.$target);

      _this.$tooltip
        .removeClass('mdui-tooltip-open')
        .transitionEnd(function () {
          transitionEnd(_this);
        });
    };

    /**
     * 切换 Tooltip 状态
     */
    Tooltip.prototype.toggle = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        _this.close();
      } else if (_this.state === 'closing' || _this.state === 'closed') {
        _this.open();
      }
    };

    /**
     * 获取 Tooltip 状态
     * @returns {'opening'|'opened'|'closing'|'closed'}
     */
    Tooltip.prototype.getState = function () {
      return this.state;
    };

    /**
     * 销毁 Tooltip
     */
    /*Tooltip.prototype.destroy = function () {
      var _this = this;
      clearTimeout(_this.timeoutId);
      $.data(_this.target, 'mdui.tooltip', null);
      $.remove(_this.tooltip);
    };*/

    return Tooltip;

  })();


  /**
   * =============================================================================
   * ************   Tooltip DATA API   ************
   * =============================================================================
   */

  $(function () {
    // mouseenter 不能冒泡,所以这里用 mouseover 代替
    $document.on('touchstart mouseover', '[mdui-tooltip]', function () {
      var $this = $(this);

      var inst = $this.data('mdui.tooltip');
      if (!inst) {
        var options = parseOptions($this.attr('mdui-tooltip'));
        inst = new mdui.Tooltip($this, options);
        $this.data('mdui.tooltip', inst);
      }
    });
  });


  /**
   * =============================================================================
   * ************   Snackbar   ************
   * =============================================================================
   */

  (function () {

    /**
     * 当前打开着的 Snackbar
     */
    var currentInst;

    /**
     * 对列名
     * @type {string}
     */
    var queueName = '__md_snackbar';

    var DEFAULT = {
      message: '',                    // 文本内容
      timeout: 4000,                  // 在用户没有操作时多长时间自动隐藏
      buttonText: '',                 // 按钮的文本
      buttonColor: '',                // 按钮的颜色,支持 blue #90caf9 rgba(...)
      closeOnButtonClick: true,       // 点击按钮时关闭
      closeOnOutsideClick: true,      // 触摸或点击屏幕其他地方时关闭
      onClick: function () {          // 在 Snackbar 上点击的回调
      },

      onButtonClick: function () {    // 点击按钮的回调
      },

      onClose: function () {          // 关闭动画开始时的回调
      },
    };

    /**
     * 点击 Snackbar 外面的区域关闭
     * @param e
     */
    var closeOnOutsideClick = function (e) {
      var $target = $(e.target);
      if (!$target.hasClass('mdui-snackbar') && !$target.parents('.mdui-snackbar').length) {
        currentInst.close();
      }
    };

    /**
     * Snackbar 实例
     * @param opts
     * @constructor
     */
    function Snackbar(opts) {
      var _this = this;

      _this.options = $.extend({}, DEFAULT, (opts || {}));

      // message 参数必须
      if (!_this.options.message) {
        return;
      }

      _this.state = 'closed';

      _this.timeoutId = false;

      // 按钮颜色
      var buttonColorStyle = '';
      var buttonColorClass = '';

      if (
        _this.options.buttonColor.indexOf('#') === 0 ||
        _this.options.buttonColor.indexOf('rgb') === 0
      ) {
        buttonColorStyle = 'style="color:' + _this.options.buttonColor + '"';
      } else if (_this.options.buttonColor !== '') {
        buttonColorClass = 'mdui-text-color-' + _this.options.buttonColor;
      }

      // 添加 HTML
      _this.$snackbar = $(
        '<div class="mdui-snackbar">' +
          '<div class="mdui-snackbar-text">' +
            _this.options.message +
          '</div>' +
          (_this.options.buttonText ?
            ('<a href="javascript:void(0)" ' +
            'class="mdui-snackbar-action mdui-btn mdui-ripple mdui-ripple-white ' +
              buttonColorClass + '" ' +
              buttonColorStyle + '>' +
              _this.options.buttonText +
            '</a>') :
            ''
          ) +
        '</div>')
        .appendTo($body);

      // 设置位置
      _this.$snackbar
        .transform('translateY(' + _this.$snackbar[0].clientHeight + 'px)')
        .css('left', (document.body.clientWidth - _this.$snackbar[0].clientWidth) / 2 + 'px')
        .addClass('mdui-snackbar-transition');
    }

    /**
     * 打开 Snackbar
     */
    Snackbar.prototype.open = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        return;
      }

      // 如果当前有正在显示的 Snackbarï¼Œåˆ™å…ˆåŠ å…¥é˜Ÿåˆ—ï¼Œç­‰æ—§ Snackbar 关闭后再打开
      if (currentInst) {
        queue.queue(queueName, function () {
          _this.open();
        });

        return;
      }

      currentInst = _this;

      // 开始打开
      _this.state = 'opening';
      _this.$snackbar
        .transform('translateY(0)')
        .transitionEnd(function () {
          if (_this.state !== 'opening') {
            return;
          }

          _this.state = 'opened';

          // 有按钮时绑定事件
          if (_this.options.buttonText) {
            _this.$snackbar
              .find('.mdui-snackbar-action')
              .on('click', function () {
                _this.options.onButtonClick();
                if (_this.options.closeOnButtonClick) {
                  _this.close();
                }
              });
          }

          // 点击 snackbar 的事件
          _this.$snackbar.on('click', function (e) {
            if (!$(e.target).hasClass('mdui-snackbar-action')) {
              _this.options.onClick();
            }
          });

          // 点击 Snackbar 外面的区域关闭
          if (_this.options.closeOnOutsideClick) {
            $document.on(TouchHandler.start, closeOnOutsideClick);
          }

          // 超时后自动关闭
          _this.timeoutId = setTimeout(function () {
            _this.close();
          }, _this.options.timeout);
        });
    };

    /**
     * 关闭 Snackbar
     */
    Snackbar.prototype.close = function () {
      var _this = this;

      if (_this.state === 'closing' || _this.state === 'closed') {
        return;
      }

      if (_this.timeoutId) {
        clearTimeout(_this.timeoutId);
      }

      if (_this.options.closeOnOutsideClick) {
        $document.off(TouchHandler.start, closeOnOutsideClick);
      }

      _this.state = 'closing';
      _this.options.onClose();

      _this.$snackbar
        .transform('translateY(' + _this.$snackbar[0].clientHeight + 'px)')
        .transitionEnd(function () {
          if (_this.state !== 'closing') {
            return;
          }

          currentInst = null;
          _this.state = 'closed';
          _this.$snackbar.remove();
          queue.dequeue(queueName);
        });
    };

    /**
     * 打开 Snackbar
     * @param params
     */
    mdui.snackbar = function (params) {
      var inst = new Snackbar(params);

      inst.open();
      return inst;
    };

  })();


  /**
   * =============================================================================
   * ************   Bottom navigation åº•éƒ¨å¯¼èˆªæ    ************
   * =============================================================================
   */

  (function () {

    // 切换导航项
    $document.on('click', '.mdui-bottom-nav>a', function () {
      var $this = $(this);
      var $bottomNav = $this.parent();
      var isThis;
      $bottomNav.children('a').each(function (i, item) {
        isThis = $this.is(item);
        if (isThis) {
          componentEvent('change', 'bottomNav', null, $bottomNav, {
            index: i,
          });
        }

        $(item)[isThis ? 'addClass' : 'removeClass']('mdui-bottom-nav-active');
      });
    });

    // 滚动时隐藏 mdui-bottom-nav-scroll-hide
    $('.mdui-bottom-nav-scroll-hide').each(function () {
      var $this = $(this);
      var inst = new mdui.Headroom($this, {
        pinnedClass: 'mdui-headroom-pinned-down',
        unpinnedClass: 'mdui-headroom-unpinned-down',
      });
      $this.data('mdui.headroom', inst);
    });

  })();


  /**
   * =============================================================================
   * ************   Spinner 圆形进度条   ************
   * =============================================================================
   */

  (function () {
    /**
     * layer çš„ HTML 结构
     */
    var layerHTML = function () {
      var i = arguments.length ? arguments[0] : false;

      return '<div class="mdui-spinner-layer ' + (i ? 'mdui-spinner-layer-' + i : '') + '">' +
                 '<div class="mdui-spinner-circle-clipper mdui-spinner-left">' +
               '<div class="mdui-spinner-circle"></div>' +
               '</div>' +
               '<div class="mdui-spinner-gap-patch">' +
                 '<div class="mdui-spinner-circle"></div>' +
               '</div>' +
               '<div class="mdui-spinner-circle-clipper mdui-spinner-right">' +
                 '<div class="mdui-spinner-circle"></div>' +
               '</div>' +
             '</div>';
    };

    /**
     * å¡«å…… HTML
     * @param spinner
     */
    var fillHTML = function (spinner) {
      var $spinner = $(spinner);
      var layer;
      if ($spinner.hasClass('mdui-spinner-colorful')) {
        layer = layerHTML('1') + layerHTML('2') + layerHTML('3') + layerHTML('4');
      } else {
        layer = layerHTML();
      }

      $spinner.html(layer);
    };

    /**
     * é¡µé¢åŠ è½½å®ŒåŽè‡ªåŠ¨å¡«å…… HTML 结构
     */
    $(function () {
      $('.mdui-spinner').each(function () {
        fillHTML(this);
      });
    });

    /**
     * 更新圆形进度条
     */
    mdui.updateSpinners = function () {
      $(arguments.length ? arguments[0] : '.mdui-spinner').each(function () {
        fillHTML(this);
      });
    };

  })();



  /**
   * =============================================================================
   * ************   Expansion panel 可扩展面板   ************
   * =============================================================================
   */

  mdui.Panel = (function () {

    function Panel(selector, opts) {
      return new CollapsePrivate(selector, opts, {
        item: 'mdui-panel-item',
        itemOpen: 'mdui-panel-item-open',
        header: 'mdui-panel-item-header',
        body: 'mdui-panel-item-body',
      }, 'panel');
    }

    return Panel;

  })();


  /**
   * =============================================================================
   * ************   Expansion panel 自定义属性   ************
   * =============================================================================
   */

  $(function () {
    $('[mdui-panel]').each(function () {
      var $target = $(this);

      var inst = $target.data('mdui.panel');
      if (!inst) {
        var options = parseOptions($target.attr('mdui-panel'));
        inst = new mdui.Panel($target, options);
        $target.data('mdui.panel', inst);
      }
    });
  });


  /**
   * =============================================================================
   * ************   Menu 菜单   ************
   * =============================================================================
   */

  mdui.Menu = (function () {

    /**
     * 默认参数
     */
    var DEFAULT = {
      position: 'auto',         // 菜单位置 top、bottom、center、auto
      align: 'auto',            // èœå•å’Œè§¦å‘å®ƒçš„å…ƒç´ çš„å¯¹é½æ–¹å¼ left、right、center、auto
      gutter: 16,               // 菜单距离窗口边缘的最小距离,单位 px
      fixed: false,             // 是否使菜单固定在窗口,不随滚动条滚动
      covered: 'auto',          // èœå•æ˜¯å¦è¦†ç›–åœ¨è§¦å‘å®ƒçš„å…ƒç´ ä¸Šï¼Œtrue、false。auto 时简单菜单覆盖,级联菜单不覆盖
      subMenuTrigger: 'hover',  // 子菜单的触发方式 hover、click
      subMenuDelay: 200,        // 子菜单的触发延时,仅在 submenuTrigger 为 hover 有效
    };

    /**
     * 调整主菜单位置
     * @param _this 实例
     */
    var readjust = function (_this) {
      var menuLeft;
      var menuTop;

      // 菜单位置和方向
      var position;
      var align;

      // window 窗口的宽度和高度
      var windowHeight = $window.height();
      var windowWidth = $window.width();

      // 配置参数
      var gutter = _this.options.gutter;
      var isCovered = _this.isCovered;
      var isFixed = _this.options.fixed;

      // 动画方向参数
      var transformOriginX;
      var transformOriginY;

      // 菜单的原始宽度和高度
      var menuWidth = _this.$menu.width();
      var menuHeight = _this.$menu.height();

      var $anchor = _this.$anchor;

      // è§¦å‘èœå•çš„å…ƒç´ åœ¨çª—å£ä¸­çš„ä½ç½®
      var anchorTmp = $anchor[0].getBoundingClientRect();
      var anchorTop = anchorTmp.top;
      var anchorLeft = anchorTmp.left;
      var anchorHeight = anchorTmp.height;
      var anchorWidth = anchorTmp.width;
      var anchorBottom = windowHeight - anchorTop - anchorHeight;
      var anchorRight = windowWidth - anchorLeft - anchorWidth;

      // è§¦å‘å…ƒç´ ç›¸å¯¹å…¶æ‹¥æœ‰å®šä½å±žæ€§çš„çˆ¶å…ƒç´ çš„ä½ç½®
      var anchorOffsetTop = $anchor[0].offsetTop;
      var anchorOffsetLeft = $anchor[0].offsetLeft;

      // ===============================
      // ================= 自动判断菜单位置
      // ===============================
      if (_this.options.position === 'auto') {

        // 判断下方是否放得下菜单
        if (anchorBottom + (isCovered ? anchorHeight : 0) > menuHeight + gutter) {
          position = 'bottom';
        }

        // 判断上方是否放得下菜单
        else if (anchorTop + (isCovered ? anchorHeight : 0) > menuHeight + gutter) {
          position = 'top';
        }

        // 上下都放不下,居中显示
        else {
          position = 'center';
        }
      } else {
        position = _this.options.position;
      }

      // ===============================
      // ============== 自动判断菜单对齐方式
      // ===============================
      if (_this.options.align === 'auto') {

        // 判断右侧是否放得下菜单
        if (anchorRight + anchorWidth > menuWidth + gutter) {
          align = 'left';
        }

        // 判断左侧是否放得下菜单
        else if (anchorLeft + anchorWidth > menuWidth + gutter) {
          align = 'right';
        }

        // 左右都放不下,居中显示
        else {
          align = 'center';
        }
      } else {
        align = _this.options.align;
      }

      // ===============================
      // ==================== 设置菜单位置
      // ===============================
      if (position === 'bottom') {
        transformOriginY = '0';

        menuTop =
          (isCovered ? 0 : anchorHeight) +
          (isFixed ? anchorTop : anchorOffsetTop);

      } else if (position === 'top') {
        transformOriginY = '100%';

        menuTop =
          (isCovered ? anchorHeight : 0) +
          (isFixed ? (anchorTop - menuHeight) : (anchorOffsetTop - menuHeight));

      } else {
        transformOriginY = '50%';

        // =====================在窗口中居中
        // 显示的菜单的高度,简单菜单高度不超过窗口高度,若超过了则在菜单内部显示滚动条
        // 级联菜单内部不允许出现滚动条
        var menuHeightTemp = menuHeight;

        // 简单菜单比窗口高时,限制菜单高度
        if (!_this.$menu.hasClass('mdui-menu-cascade')) {
          if (menuHeight + gutter * 2 > windowHeight) {
            menuHeightTemp = windowHeight - gutter * 2;
            _this.$menu.height(menuHeightTemp);
          }
        }

        menuTop =
          (windowHeight - menuHeightTemp) / 2 +
          (isFixed ? 0 : (anchorOffsetTop - anchorTop));
      }

      _this.$menu.css('top', menuTop + 'px');

      // ===============================
      // ================= 设置菜单对齐方式
      // ===============================
      if (align === 'left') {
        transformOriginX = '0';

        menuLeft = isFixed ? anchorLeft : anchorOffsetLeft;

      } else if (align === 'right') {
        transformOriginX = '100%';

        menuLeft = isFixed ?
          (anchorLeft + anchorWidth - menuWidth) :
          (anchorOffsetLeft + anchorWidth - menuWidth);
      } else {
        transformOriginX = '50%';

        //=======================在窗口中居中
        // 显示的菜单的宽度,菜单宽度不能超过窗口宽度
        var menuWidthTemp = menuWidth;

        // 菜单比窗口宽,限制菜单宽度
        if (menuWidth + gutter * 2 > windowWidth) {
          menuWidthTemp = windowWidth - gutter * 2;
          _this.$menu.width(menuWidthTemp);
        }

        menuLeft =
          (windowWidth - menuWidthTemp) / 2 +
          (isFixed ? 0 : anchorOffsetLeft - anchorLeft);
      }

      _this.$menu.css('left', menuLeft + 'px');

      // 设置菜单动画方向
      _this.$menu.transformOrigin(transformOriginX + ' ' + transformOriginY);
    };

    /**
     * 调整子菜单的位置
     * @param $submenu
     */
    var readjustSubmenu = function ($submenu) {
      var $item = $submenu.parent('.mdui-menu-item');

      var submenuTop;
      var submenuLeft;

      // 子菜单位置和方向
      var position; // top、bottom
      var align; // left、right

      // window 窗口的宽度和高度
      var windowHeight = $window.height();
      var windowWidth = $window.width();

      // 动画方向参数
      var transformOriginX;
      var transformOriginY;

      // 子菜单的原始宽度和高度
      var submenuWidth = $submenu.width();
      var submenuHeight = $submenu.height();

      // 触发子菜单的菜单项的宽度高度
      var itemTmp = $item[0].getBoundingClientRect();
      var itemWidth = itemTmp.width;
      var itemHeight = itemTmp.height;
      var itemLeft = itemTmp.left;
      var itemTop = itemTmp.top;

      // ===================================
      // ===================== 判断菜单上下位置
      // ===================================

      // 判断下方是否放得下菜单
      if (windowHeight - itemTop > submenuHeight) {
        position = 'bottom';
      }

      // 判断上方是否放得下菜单
      else if (itemTop + itemHeight > submenuHeight) {
        position = 'top';
      }

      // 默认放在下方
      else {
        position = 'bottom';
      }

      // ====================================
      // ====================== 判断菜单左右位置
      // ====================================

      // 判断右侧是否放得下菜单
      if (windowWidth - itemLeft - itemWidth > submenuWidth) {
        align = 'left';
      }

      // 判断左侧是否放得下菜单
      else if (itemLeft > submenuWidth) {
        align = 'right';
      }

      // 默认放在右侧
      else {
        align = 'left';
      }

      // ===================================
      // ======================== 设置菜单位置
      // ===================================
      if (position === 'bottom') {
        transformOriginY = '0';
        submenuTop = '0';
      } else if (position === 'top') {
        transformOriginY = '100%';
        submenuTop = -submenuHeight + itemHeight;
      }

      $submenu.css('top', submenuTop + 'px');

      // ===================================
      // ===================== 设置菜单对齐方式
      // ===================================
      if (align === 'left') {
        transformOriginX = '0';
        submenuLeft = itemWidth;
      } else if (align === 'right') {
        transformOriginX = '100%';
        submenuLeft = -submenuWidth;
      }

      $submenu.css('left', submenuLeft + 'px');

      // 设置菜单动画方向
      $submenu.transformOrigin(transformOriginX + ' ' + transformOriginY);
    };

    /**
     * 打开子菜单
     * @param $submenu
     */
    var openSubMenu = function ($submenu) {
      readjustSubmenu($submenu);

      $submenu
        .addClass('mdui-menu-open')
        .parent('.mdui-menu-item')
        .addClass('mdui-menu-item-active');
    };

    /**
     * 关闭子菜单,及其嵌套的子菜单
     * @param $submenu
     */
    var closeSubMenu = function ($submenu) {
      // 关闭子菜单
      $submenu
        .removeClass('mdui-menu-open')

        // ç§»é™¤æ¿€æ´»çŠ¶æ€çš„æ ·å¼
        .parent('.mdui-menu-item')
        .removeClass('mdui-menu-item-active');

      // 循环关闭嵌套的子菜单
      $submenu.find('.mdui-menu').each(function () {
        $(this)
          .removeClass('mdui-menu-open')
          .parent('.mdui-menu-item')
          .removeClass('mdui-menu-item-active');
      });
    };

    /**
     * 切换子菜单状态
     * @param $submenu
     */
    var toggleSubMenu = function ($submenu) {
      if ($submenu.hasClass('mdui-menu-open')) {
        closeSubMenu($submenu);
      } else {
        openSubMenu($submenu);
      }
    };

    /**
     * 绑定子菜单事件
     * @param inst 实例
     */
    var bindSubMenuEvent = function (inst) {
      // 点击打开子菜单
      inst.$menu.on('click', '.mdui-menu-item', function (e) {
        var $this = $(this);
        var $target = $(e.target);

        // 禁用状态菜单不操作
        if ($this.attr('disabled') !== null) {
          return;
        }

        // 没有点击在子菜单的菜单项上时,不操作(点在了子菜单的空白区域、或分隔线上)
        if ($target.is('.mdui-menu') || $target.is('.mdui-divider')) {
          return;
        }

        // 阻止冒泡,点击菜单项时只在最后一级的 mdui-menu-item 上生效,不向上冒泡
        if (!$target.parents('.mdui-menu-item').eq(0).is($this)) {
          return;
        }

        // 当前菜单的子菜单
        var $submenu = $this.children('.mdui-menu');

        // 先关闭除当前子菜单外的所有同级子菜单
        $this.parent('.mdui-menu').children('.mdui-menu-item').each(function () {
          var $tmpSubmenu = $(this).children('.mdui-menu');
          if (
            $tmpSubmenu.length &&
            (!$submenu.length || !$tmpSubmenu.is($submenu))
          ) {
            closeSubMenu($tmpSubmenu);
          }
        });

        // 切换当前子菜单
        if ($submenu.length) {
          toggleSubMenu($submenu);
        }
      });

      if (inst.options.subMenuTrigger === 'hover') {
        // 临时存储 setTimeout 对象
        var timeout;

        var timeoutOpen;
        var timeoutClose;

        inst.$menu.on('mouseover mouseout', '.mdui-menu-item', function (e) {
          var $this = $(this);
          var eventType = e.type;
          var $relatedTarget = $(e.relatedTarget);

          // 禁用状态的菜单不操作
          if ($this.attr('disabled') !== null) {
            return;
          }

          // 用 mouseover 模拟 mouseenter
          if (eventType === 'mouseover') {
            if (!$this.is($relatedTarget) && $.contains($this[0], $relatedTarget[0])) {
              return;
            }
          }

          // 用 mouseout 模拟 mouseleave
          else if (eventType === 'mouseout') {
            if ($this.is($relatedTarget) || $.contains($this[0], $relatedTarget[0])) {
              return;
            }
          }

          // 当前菜单项下的子菜单,未必存在
          var $submenu = $this.children('.mdui-menu');

          // é¼ æ ‡ç§»å…¥èœå•é¡¹æ—¶ï¼Œæ˜¾ç¤ºèœå•é¡¹ä¸‹çš„å­èœå•
          if (eventType === 'mouseover') {
            if ($submenu.length) {

              // 当前子菜单准备打开时,如果当前子菜单正准备着关闭,不用再关闭了
              var tmpClose = $submenu.data('timeoutClose.mdui.menu');
              if (tmpClose) {
                clearTimeout(tmpClose);
              }

              // 如果当前子菜单已经打开,不操作
              if ($submenu.hasClass('mdui-menu-open')) {
                return;
              }

              // 当前子菜单准备打开时,其他准备打开的子菜单不用再打开了
              clearTimeout(timeoutOpen);

              // 准备打开当前子菜单
              timeout = timeoutOpen = setTimeout(function () {
                openSubMenu($submenu);
              }, inst.options.subMenuDelay);

              $submenu.data('timeoutOpen.mdui.menu', timeout);
            }
          }

          // é¼ æ ‡ç§»å‡ºèœå•é¡¹æ—¶ï¼Œå…³é—­èœå•é¡¹ä¸‹çš„å­èœå•
          else if (eventType === 'mouseout') {
            if ($submenu.length) {

              // é¼ æ ‡ç§»å‡ºèœå•é¡¹æ—¶ï¼Œå¦‚æžœå½“å‰èœå•é¡¹ä¸‹çš„å­èœå•æ­£å‡†å¤‡æ‰“å¼€ï¼Œä¸ç”¨å†æ‰“å¼€äº†
              var tmpOpen = $submenu.data('timeoutOpen.mdui.menu');
              if (tmpOpen) {
                clearTimeout(tmpOpen);
              }

              // 准备关闭当前子菜单
              timeout = timeoutClose = setTimeout(function () {
                closeSubMenu($submenu);
              }, inst.options.subMenuDelay);

              $submenu.data('timeoutClose.mdui.menu', timeout);
            }
          }
        });
      }
    };

    /**
     * 菜单
     * @param anchorSelector ç‚¹å‡»è¯¥å…ƒç´ è§¦å‘èœå•
     * @param menuSelector 菜单
     * @param opts 配置项
     * @constructor
     */
    function Menu(anchorSelector, menuSelector, opts) {
      var _this = this;

      // 触发菜单的元ç´
      _this.$anchor = $(anchorSelector).eq(0);
      if (!_this.$anchor.length) {
        return;
      }

      // 已通过自定义属性实例化过,不再重复实例化
      var oldInst = _this.$anchor.data('mdui.menu');
      if (oldInst) {
        return oldInst;
      }

      _this.$menu = $(menuSelector).eq(0);

      // 触发菜单的元素 å’Œ èœå•å¿…é¡»æ˜¯åŒçº§çš„å…ƒç´ ï¼Œå¦åˆ™èœå•å¯èƒ½ä¸èƒ½å®šä½
      if (!_this.$anchor.siblings(_this.$menu).length) {
        return;
      }

      _this.options = $.extend({}, DEFAULT, (opts || {}));
      _this.state = 'closed';

      // 是否是级联菜单
      _this.isCascade = _this.$menu.hasClass('mdui-menu-cascade');

      // covered 参数处理
      if (_this.options.covered === 'auto') {
        _this.isCovered = !_this.isCascade;
      } else {
        _this.isCovered = _this.options.covered;
      }

      // 点击触发菜单切换
      _this.$anchor.on('click', function () {
        _this.toggle();
      });

      // 点击菜单外面区域关闭菜单
      $document.on('click touchstart', function (e) {
        var $target = $(e.target);
        if (
          (_this.state === 'opening' || _this.state === 'opened') &&
            !$target.is(_this.$menu) &&
            !$.contains(_this.$menu[0], $target[0]) &&
            !$target.is(_this.$anchor) &&
            !$.contains(_this.$anchor[0], $target[0])
        ) {
          _this.close();
        }
      });

      // 点击不含子菜单的菜单条目关闭菜单
      $document.on('click', '.mdui-menu-item', function (e) {
        var $this = $(this);
        if (!$this.find('.mdui-menu').length && $this.attr('disabled') === null) {
          _this.close();
        }
      });

      // ç»‘å®šç‚¹å‡»æˆ–é¼ æ ‡ç§»å…¥å«å­èœå•çš„æ¡ç›®çš„äº‹ä»¶
      bindSubMenuEvent(_this);

      // 窗口大小变化时,重新调整菜单位置
      $window.on('resize', $.throttle(function () {
        readjust(_this);
      }, 100));
    }

    /**
     * 切换菜单状态
     */
    Menu.prototype.toggle = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        _this.close();
      } else if (_this.state === 'closing' || _this.state === 'closed') {
        _this.open();
      }
    };

    /**
     * 动画结束回调
     * @param inst
     */
    var transitionEnd = function (inst) {
      if (inst.state === 'opening') {
        inst.state = 'opened';
        componentEvent('opened', 'menu', inst, inst.$menu);
      }

      if (inst.state === 'closing') {
        inst.state = 'closed';
        componentEvent('closed', 'menu', inst, inst.$menu);

        // å…³é—­åŽï¼Œæ¢å¤èœå•æ ·å¼åˆ°é»˜è®¤çŠ¶æ€ï¼Œå¹¶æ¢å¤ fixed 定位
        inst.$menu.css({
          top: '',
          left: '',
          width: '',
          position: 'fixed',
        });
      }
    };

    /**
     * 打开菜单
     */
    Menu.prototype.open = function () {
      var _this = this;

      if (_this.state === 'opening' || _this.state === 'opened') {
        return;
      }

      _this.state = 'opening';
      componentEvent('open', 'menu', _this, _this.$menu);

      // 调整菜单位置
      readjust(_this);

      _this.$menu

        // 菜单隐藏状态使用使用 fixed 定位。
        .css('position', _this.options.fixed ? 'fixed' : 'absolute')

        // 打开菜单
        .addClass('mdui-menu-open')

        // 打开动画完成后
        .transitionEnd(function () {
          transitionEnd(_this);
        });
    };

    /**
     * 关闭菜单
     */
    Menu.prototype.close = function () {
      var _this = this;
      if (_this.state === 'closing' || _this.state === 'closed') {
        return;
      }

      _this.state = 'closing';
      componentEvent('close', 'menu', _this, _this.$menu);

      // 菜单开始关闭时,关闭所有子菜单
      _this.$menu.find('.mdui-menu').each(function () {
        closeSubMenu($(this));
      });

      _this.$menu
        .removeClass('mdui-menu-open')
        .transitionEnd(function () {
          transitionEnd(_this);
        });
    };

    return Menu;
  })();


  /**
   * =============================================================================
   * ************   Menu 自定义属性 API   ************
   * =============================================================================
   */

  $(function () {
    $document.on('click', '[mdui-menu]', function () {
      var $this = $(this);

      var inst = $this.data('mdui.menu');
      if (!inst) {
        var options = parseOptions($this.attr('mdui-menu'));
        var menuSelector = options.target;
        delete options.target;

        inst = new mdui.Menu($this, menuSelector, options);
        $this.data('mdui.menu', inst);

        inst.toggle();
      }
    });
  });


  /* jshint ignore:start */
  mdui.JQ = $;
  window.mdui = mdui;
})(window, document);
/* jshint ignore:end */
</script>

Nhận xét

Đăng nhận xét