item/item.vue

<script type="text/javascript">
  /**
   * @component Item
   * @description
   *
   * ## 列表组件 / Item
   *
   * Item组件是List组件的子组件, 两者配合使用.
   *
   * ### 关于其余组件
   *
   * 列表组件中的每一个Item将在这里定义, 其中包括**Item/ListHeader/ItemGroup/ItemDivider**等, 他们的使用方式基本一样, 这里统一说明.
   *
   *
   * ### ItemDivider组件
   *
   * 加 `[sticky]` 属性可实现吸顶效果
   *
   * ### 如何使用
   *
   * ### Item组件
   *
   * - 加 `[no-lines]` 属性可去除边框
   * - 在item中的Icon上加属性`[large],[small]`可控制大小
   *
   * ### 关于跳转
   *
   * item组件将使用v-router的router-link组件中的部分同名方法, 并执行对应的跳转
   *
   * ### 如何引入
   *
   * ```
   * // 引入
   * import { List, ListHeader, ItemGroup, Item, ItemDivider } from 'vimo'
   * // 安装
   * Vue.component(List.name, List)
   * Vue.component(ListHeader.name, ListHeader)
   * Vue.component(ItemGroup.name, ItemGroup)
   * Vue.component(Item.name, Item)
   * Vue.component(ItemDivider.name, ItemDivider)
   * // 或者
   * export default{
   *   components: {
   *    List, ListHeader, ItemGroup, Item, ItemDivider
   *  }
   * }
   * ```
   *
   * @props {String} [mode='ios'] - 模式
   * @props {String} [color] - 颜色
   * @props {any} [to] - 路由, 这部分用法请参开vue-router, 这里是对其移植
   * @props {Boolean} [append] - 路由是否append
   * @props {Boolean} [replace] - 路由进行方式, 默认为push
   *
   *
   * @slot 空 - 放置在中间, 默认位置
   * @slot item-left - 放置在左边
   * @slot item-right - 放置在左边
   *
   * @demo #/list
   * @see component:List
   * @see http://router.vuejs.org/zh-cn/index.html
   *
   * @usage
   * <List>
   *    <ListHeader>
   *            setting
   *        <Button slot="item-right" clear>
   *            <Icon name="cog"></Icon>
   *        </Button>
   *    </ListHeader>
   *    <ItemGroup>
   *        <Item>
   *            <Icon slot="item-left" color="danger" name="plane"></Icon>
   *            <span>Airplane Mode</span>
   *            <Toggle slot="item-right" @ionChange="toggleChange"
   *                :checked="toggleValue"></Toggle>
   *        </Item>
   *    <Item button>
   *            <Icon slot="item-left" color="primary" name="wifi"></Icon>
   *                Wi-Fi
   *            <Note slot="item-right">The Interwebz</Note>
   *        </Item>
   *        <Item button>
   *            <Icon slot="item-left" color="primary" name="bluetooth"></Icon>
   *                Bluetooth
   *            <Note slot="item-right">Off</Note>
   *        </Item>
   *    </ItemGroup>
   *    <ItemDivider color="primary">
   *        Other Setting
   *        <Button slot="item-right" outline color="light">Clear</Button>
   *    </ItemDivider>
   *    <Item button>
   *            <Icon slot="item-left" color="secondary" name="call"></Icon>
   *            Cellular
   *    </Item>
   *    <Item button>
   *         <Icon slot="item-left" color="secondary" name="link"></Icon>
   *            Personal Hotspot
   *        <Note slot="item-right">Off</Note>
   *    </Item>
   * </List>
   *
   * */
  import ItemMixin from './item-mixin.vue'
  import { isPresent, isString } from '../../util/type'

  export default {
    mixins: [ItemMixin],
    name: 'Item',
    data () {
      return {
        isInMenu: this.wait // 判断是否在menu组件中, 如果在menu中, 则
      }
    },
    props: {
      /**
       * 指向跳转
       * 当被点击后,内部会立刻把 to 的值传到 router.push()
       * 所以这个值可以是一个字符串或者是描述目标位置的对象
       * */
      to: [String, Object],

      append: Boolean,

      /**
       * 设置 replace 属性的话,当点击时,会调用 router.replace()
       * 而不是 router.push(),于是导航后不会留下 history 记录。
       * */
      replace: Boolean,

      /**
       * 如果是在menus中, 可以设置这个值, 当menus完全关闭时再出发跳转动作
       * */
      wait: Boolean
    },
    methods: {
      /**
       * 类似于a标签跳转
       * */
      $_clickHandler ($event) {
        const _this = this
        const router = this.$router
        const current = this.$route
        let _to = this.to
        if (isPresent(router) && isPresent(current) && isPresent(_to)) {
          if (isString(_to)) {
            _to = {
              name: _to
            }
          }

          // 返回数据: {location, route, href}
          const {location} = router.resolve(_to, current, this.append)

          // 如果在menu跳转, 则需要等待menu关闭后再跳转
          if (this.isInMenu) {
            this.$menu.close()
            this.$root && this.$root.$on('onMenuClosed', directToHandler)
          } else {
            // 正常情况
            doRedirect()
          }

          // 事件处理函数
          // eslint-disable-next-line no-inner-declarations
          function directToHandler () {
            _this.$root && _this.$root.$off('onMenuClosed', directToHandler)
            doRedirect()
          }

          // 跳转
          // eslint-disable-next-line no-inner-declarations
          function doRedirect () {
            if (_this.replace) {
              router.replace(location)
            } else {
              router.push(location)
            }
          }
        } else {
          this.$emit('click', $event)
        }
      },
      /**
       * 获取组件类Label的文本
       * */
      getLabelText () {
        let list = []
        if (this.$slots['default'] && this.$slots['default'].length > 0) {
          list = this.$slots['default']
        }
        for (let i = 0, len = list.length; len > i; i++) {
          let item = list[i]
          let hasValue = !!item.tag || (!!item.text && !!item.text.trim())
          if (hasValue && item.elm && item.elm.textContent) {
            return item.elm.textContent.toString().trim()
          }
        }
        return ''
      }
    }
  }
</script>