3. 添加方法

继承的子类已经完成了,接下来是继承一些特定的方法,以完成我们的业务需求。

固定下拉按钮的内容

MIP Shell 基类在每个页面的大致处理过程是:

  1. 读取(自身标签内部的)页面配置
  2. 根据配置渲染/更新显示内容(如头部标题栏或其他额外的内容)
  3. 绑定并响应事件

如果我们要固定下拉按钮的内容,则应该在第一步完成后,第二步执行之前介入控制。MIP Shell 基类为我们提供了 processShellConfig 方法,参数只有一个,为当前读取到的 Shell 配置。因此我们只需要修改这个参数即可,如下:

  1. processShellConfig(shellConfig) {
  2. // 强制修改 HTML 中的按钮配置
  3. shellConfig.routes.forEach(route => {
  4. route.buttonGroup = [{
  5. "name": "setting",
  6. "text": "设置"
  7. },
  8. {
  9. "name": "cancel",
  10. "text": "取消"
  11. }]
  12. })
  13. }

这样无论页面上的 Shell 配置如何编写都会被忽略,转而使用我们设置的这两个按钮。(按钮的响应操作在之后统一处理)

创建底部栏

除了头部标题栏之外,我们还需要一个独立于每个页面之外的底部设置栏。要实现这个需求,需要在 Shell 渲染头部之后介入,把我们想要的底部也一起进行渲染。这里我们会用到基类提供的 renderOtherParts 方法:

  1. renderOtherParts () {
  2. this.$footerWrapper = document.createElement('mip-fixed')
  3. this.$footerWrapper.setAttribute('type', 'bottom')
  4. this.$footerWrapper.classList.add('mip-shell-footer-wrapper')
  5. this.$footer = document.createElement('div')
  6. this.$footer.classList.add('mip-shell-footer', 'mip-border', 'mip-border-top')
  7. this.$footer.innerHTML = this.renderFooter()
  8. this.$footerWrapper.appendChild(this.$footer)
  9. document.body.appendChild(this.$footerWrapper)
  10. }
  11. renderFooter() {
  12. let pageMeta = this.currentPageMeta
  13. // 只为了简便,直接输出了一个字符串
  14. return 'hello ${pageMeta.header.title}!'
  15. }

这里有几个注意点:

  1. renderOtherParts 本身没有参数,但可以通过 this.currentPageMeta 来获取当前页面的 Shell 配置,从而进行绘制。
  2. renderFooter 是子类方法,而不是继承自父类的。之所以要把 绘制挂载 独立开来,是为了重用考虑。因为后续更新时只需要 绘制 而不需要 挂载
  3. 如果需要创建 position: fixed 的 DOM 元素(如底部菜单栏),应当使用 <mip-fixed> 作为标签名,而非其他如 <div> 等 HTML 标准标签。这主要是为了解决 iOS 的 iframe 中 fixed 元素滚动抖动的 BUG。

更新底部栏

MIP 页面首次进入时会调用 renderOtherParts() 方法进行初始渲染。而后续切换页面时,MIP 会将目标页面的 meta 信息设置为 this.currentPageMeta 并调用 updateOtherParts() 方法以更新自定义部件。所以我们也要在这里更新底部栏。

刚才也提到过,在 updateOtherParts() 方法中,开发者仅需要更新 HTML 即可,不需要像 renderOtherParts() 那样创建 DOM 并插入到页面中。也因此,将 renderFooter() 独立出来有利于这里继续调用。示例如下:

  1. updateOtherParts() {
  2. this.$footer.innerHTML = this.renderFooter()
  3. }

绑定事件

目前为止我们处理了两部分内容:头部固定了两个按钮,以及创建了一个底部栏。这里我们要为这两部分绑定事件。

头部按钮

头部按钮的绑定我们会用到基类提供的 handleShellCustomButton 方法,参数为 buttonName,表示点击的按钮的 name 属性。

  1. handleShellCustomButton (buttonName) {
  2. if (buttonName === 'setting') {
  3. this.$footerWrapper.style.display = 'block'
  4. }
  5. }

因为示例的原因,这里只是简单调用了 display = 'block',实际项目中可能还会牵涉到蒙层,动画等等逻辑,都可以在这里扩充。

另外我们在固定按钮内容时,其实还设置了一个 namecancel 的取消按钮,在这里并没有绑定。这是因为 MIP 会对名字为 cancel 的按钮进行统一处理(动画隐藏下拉浮层),因此这里就可以省去一个判断了。

底部栏

底部栏是独立于每个页面之外的不变的内容,因此我们需要使用基类的 bindRootEvents 方法 (与之相对的是 bindAllEvents 方法处理所有页面内部的内容)。正常情况下底部栏还会有些许按钮,我们在这里给这些按钮绑定事件。

需要特别注意的是,这两个方法父类均有操作,因此 不要忘记调用 super

  1. bindRootEvents () {
  2. // 很重要!很重要!很重要!
  3. super.bindRootEvents()
  4. this.$footer.addEventListener('click', () => {
  5. // 点击隐藏底部栏
  6. this.$footerWrapper.style.display = 'none'
  7. })
  8. }

这里给整个底部都绑定了点击事件,因此可以直接使用 addEventListener。如果在实际情况中,要给按钮绑定时,需要使用 事件代理,因为每次切换页面,底部栏是会重新渲染的,因此直接使用 button.addEventListener 将会失效。

添加样式

由于有涉及创建底部栏的工作,势必需要定义底部栏的样式。这里我们就需要引入额外的样式文件。和开发自定义组件一样,只要在 js 文件的头部应用样式文件即可,如下:

  1. import './mip-shell-example.less'