title/toolbar-title.vue

<template>
    <div class="ion-title">
        <div class="toolbar-title" :class="[modeClass]"
             :style="{color:titleColor}"
             @click="titleClick" v-html="titleInner"></div>
    </div>
</template>
<script type="text/javascript">
  /**
   * @component Toolbar/Title
   * @description
   *
   *
   * ## 文档标题 / Title
   *
   * 设置顶部的title及document.title, 请使用ref获取Title组件的setTitle方法, 使用该方法会同步设置document.title(默认)
   *
   * ### 等级
   *
   * 只有在Navbar组件中的Title组件才会自动更新`document.title`的值,
   *
   *
   * ### 如何引入
   *
   * ```
   * // 引入
   * import { Toolbar, Buttons, Title } from 'vimo'
   * // 安装
   * Vue.component(Toolbar.name, Toolbar)
   * Vue.component(Title.name, Title)
   * Vue.component(Buttons.name, Buttons)
   * ```
   *
   *
   * ### 如果在支付宝中
   * 如果在支付宝中, 则使用支付宝的方式设置title及其壳子的title, 可用方法如下:
   *
   * - setTitle
   * - reset
   *
   * @props {String} [mode=ios] - 模式
   * @props {String} [title] - 标题
   * @fires component:Title#title:click
   * @see component:Toolbar
   * @usage
   * <template>
   *  <Page>
   *    <Header>
   *      <Navbar>
   *        <Title ref="title">Demo</Title>
   *      <Navbar>
   *    </Header>
   *    <Content>
   *      <h1>这里是内容</h1>
   *    </Content>
   *  </Page>
   * </template>
   *
   * ...
   *
   * computed: {
   *   titleComponent () {
   *     return this.$refs.title
   *   }
   * },
   * methods: {
   *   setAllTitle () {
   *      this.titleComponent.setTitle('title')
   * }
   *
   * */
  import { isPresent } from '../../util/type'

  export default {
    name: 'Title',
    inject: {
      appComponent: {
        from: 'appComponent',
        default: null
      },
      headerComponent: {
        from: 'headerComponent',
        default: null
      },
      navbarComponent: {
        from: 'navbarComponent',
        default: null
      }
    },
    data () {
      return {
        titleColor: null,
        titleInner: this.title
      }
    },
    props: {
      /**
       * mode 按钮风格
       * */
      mode: {
        type: String,
        default () { return isPresent(this.$config) && this.$config.get('mode', 'ios') || 'ios' }
      },
      /**
       * 设置的title值
       * */
      title: String
    },
    watch: {
      title () {
        this.titleInner = this.getTitle()
        if (this.isTitleInNavbar) {
          this.setTitle(this.titleInner)
        }
      }
    },
    computed: {
      modeClass () {
        return `toolbar-title-${this.mode}`
      },
      // 这个title组件在navbar中
      isTitleInNavbar () {
        return !!this.navbarComponent
      },
      // 包裹当前组件的Header在App组件中
      isHeaderInApp () {
        return !!this.appComponent && !!this.headerComponent && !!this.navbarComponent
      }
    },
    methods: {
      /**
       * @function getTitle
       * @description
       * 获取Title组件中的title, 兼容各种模式
       * @return {String}
       * */
      getTitle () {
        let _title = ''
        /**
         * 组件获取了传入的title值,之后通过全局注册的$setTitle方法
         * 设置document.title(此处做了兼容)
         * */
        if (this.title) {
          // prop传入title值
          // eg: <Title title="Toolbar"></Title>
          _title = this.title.trim()
        } else if (this.$slots.default && this.$slots.default[0] && this.$slots.default[0].text) {
          // 如果是直接写在ion-title中的值
          // eg: <Title>Toolbar</Title>
          _title = this.$slots.default[0].text.trim()
        } else if (this.$slots.default && this.$slots.default[0] && this.$slots.default[0].tag && this.$slots.default[0].children[0].text) {
          // 如果是这届下载ion-title中的值,并且包含一层标签的情况
          // eg: <Title>
          //      <span>Toolbar</span>
          //      <span>-</span>
          //      <span>Test</span>
          //    </Title>
          // -> Toolbar-Test
          this.$slots.default.forEach((item) => {
            if (item.children && item.children.length > 0 && item.children[0] && item.children[0].text) {
              _title += item.children[0].text.trim()
            }
          })
        }
        return _title
      },

      /**
       * @function setTitle
       * @description
       * 修改Header的title, 目前可用平台: H5/Alipay/Dingtalk
       * @param {String|Object} title - title
       * @param {String|Object} title.title - title
       * @param {String|Object} title.image - image
       * @param {boolean} [changeDocTitle=true] - 是否设置doc的title, 默认是同步设置的
       * */
      setTitle (title, changeDocTitle = true) {
        let _title = {}
        if (typeof title === 'string') {
          _title.title = title
          this.titleInner = title
        } else if (typeof title === 'object' && title.image) {
          _title.title = null
          _title.image = title.image
          this.titleInner = `<img src="${title.image}">`
        }
        if (changeDocTitle) {
          // 设置document的title, 这部分由$app处理
          this.$app && this.$app.setDocTitle(_title)
        }
      },

      /**
       * @function setTitleColor
       * @description
       * 设置Title文字的颜色
       * @param {String} color - color, 例如 #ff0000
       * */
      setTitleColor (color) {
        this.titleColor = color
      },

      /**
       * @function reset
       * @description
       * 重置Title文字的颜色, 目前可用平台: Alipay
       * */
      reset () {
        this.titleColor = null
        this.$platform && this.$platform.resetNavbarOptionButton && this.$platform.resetNavbarOptionButton()
      },

      /**
       * 初始化
       * 只在Navbar中的Title才会具有更新Title的特性!
       * 且, 一个Page只能拥有一个Navbar, 当在Navbar中设置Title, 则Title的方法
       * 将赋予页面Page(document.title),
       * @private
       * */
      init () {
        this.titleInner = this.getTitle()
        if (this.isTitleInNavbar) {
          this.setTitle(this.titleInner)
        }
        if (this.isHeaderInApp) {
          window.VM.$title = this
        }

        this.$root.$on('title:click', () => {
          this.$emit('title:click')
        })
      },

      /**
       * 点击标题时触发事件
       * @private
       * */
      titleClick () {
        if (this.isTitleInNavbar) {
          /**
           * @event component:Title#title:click
           * @description 点击title时触发
           */
          this.$emit('title:click', this)
        }
      }
    },
    mounted () {
      this.init()
    },
    activated () {
      // BugFix: #15, keep-alive模式下不更新title的问题
      if (this.isTitleInNavbar) {
        this.setTitle(this.titleInner)
      }
      if (this.isHeaderInApp) {
        window.VM.$title = this
      }
    }
  }
</script>