segment/segment.vue

  1. <template>
  2. <div class="ion-segment segment" :class="[modeClass,colorClass]">
  3. <slot></slot>
  4. </div>
  5. </template>
  6. <style lang="scss" src="./style.scss"></style>
  7. <script type="text/javascript">
  8. /**
  9. * @component Segment
  10. * @description
  11. *
  12. * ## 小标签 / Segment
  13. *
  14. * Segment组件可以说是联动的按钮组合, 他不负责路由, 只是按钮组合而已. 如果涉及路由, 请使用Tab组件, 或者自己集成路由部分.
  15. *
  16. * ### 父子组件组合
  17. *
  18. * Segment组件和SegmentButton组件是互相组合的模式, 不可分离. 父组件可使用`v-model`指令监听子组件当前的选中状态. 子组件支持异步载入, 当子组件的value没有指定, 则使用当前组件的内置文本作为其value.
  19. *
  20. * ### 父子组件通信过程
  21. *
  22. * 1. 初始化时, 子组件自己的this传递给父组件, recordChild()
  23. * 2. 子组件点击时, 调用父组件的 $_refreshChildState 函数, 传递自己的value
  24. * 3. 父组件得到value触发onChange更新v-modal值, 之后遍历子组件, 触发组件的setChecked, 传递value
  25. * 4. 子组件根据传入的value设置自己的状态
  26. *
  27. * ### 异步加载子组件
  28. *
  29. * 父组件通过被动的的方式获取对子组件的控制权, 便于异步动态初始化子组件的情形. 子组件的value是子组件的标示, 当value没有值时, 通过SegmentButton组件中的text内容获取唯一标示.
  30. *
  31. * ### 支持`v-model`指令
  32. *
  33. * 如果不使用`v-model`指令, 通过`value`属性可设置初始选中状态, 但是使用了`v-model`指令时, 动态改变value将不会触发`onChange事件`, 因为事件的触发原则是组件内部变动通知外部, 但是外部改变value不是内部行为, 这点切记.
  34. *
  35. *
  36. * ### 如何使用
  37. *
  38. * ```
  39. * // 引入
  40. * import { Segment, SegmentButton } from 'vimo'
  41. * // 安装
  42. * Vue.component(Segment.name, Segment)
  43. * Vue.component(SegmentButton.name, SegmentButton)
  44. * ```
  45. *
  46. * @props {String} color - 颜色
  47. * @props {String} mode - 样式模式
  48. * @props {String} value - 当前Segment的value, 用于触发制定value的子组件
  49. *
  50. * @fires component:Segment#onChange
  51. * @demo #/segment
  52. *
  53. * @usage
  54. * <Header>
  55. * <Navbar>
  56. * <Title>普通用法</Title>
  57. * </Navbar>
  58. * <Toolbar>
  59. * <!--content-->
  60. * <Segment v-model="fruit" @onChange="onChangeHandler">
  61. * <SegmentButton value="apple" @onSelect="onSelectHandler">Apple</SegmentButton>
  62. * <SegmentButton value="orange" @onSelect="onSelectHandler">Orange</SegmentButton>
  63. * <SegmentButton value="pear" @onSelect="onSelectHandler">Pear</SegmentButton>
  64. * <SegmentButton value="disabled" :disabled="true" @onSelect="onSelectHandler">Disabled</SegmentButton>
  65. * </Segment>
  66. * </Toolbar>
  67. * </Header>
  68. *
  69. * */
  70. import modeMixins from '../../util/mode-mixins.js'
  71. export default {
  72. name: 'Segment',
  73. mixins: [modeMixins],
  74. provide () {
  75. let _this = this
  76. return {
  77. segmentComponent: _this
  78. }
  79. },
  80. model: {
  81. prop: 'value',
  82. event: 'onChange'
  83. },
  84. props: {
  85. /**
  86. * 接收value信息
  87. * */
  88. value: [String, Number],
  89. disabled: Boolean
  90. },
  91. data () {
  92. return {
  93. // value的缓存值,因为props的value不能直接修改
  94. childComponents: [],
  95. theValue: this.value,
  96. timer: null
  97. }
  98. },
  99. watch: {
  100. value (value) {
  101. // 更新子组件状态
  102. this.$_refreshChildState(value)
  103. }
  104. },
  105. methods: {
  106. /**
  107. * 更新子组件状态
  108. * @private
  109. * */
  110. $_refreshChildState (value) {
  111. this.childComponents.forEach((childComponent) => {
  112. if (!childComponent.isDisabled) {
  113. childComponent.setState(value)
  114. }
  115. })
  116. },
  117. /**
  118. * 记录子组件, 这个由子组件自己找到并调用
  119. * @param {Object} childComponent - 子组件实例(子组件的this)
  120. * @private
  121. * */
  122. $_recordChild (childComponent) {
  123. this.childComponents.push(childComponent)
  124. this.timer && window.clearTimeout(this.timer)
  125. this.timer = window.setTimeout(() => {
  126. // 更新子组件状态
  127. this.$_refreshChildState(this.value)
  128. }, 0)
  129. },
  130. /**
  131. * 子组件点击时操作此函数
  132. * @param {string} value - 当前子组件的点击值
  133. * @private
  134. * */
  135. $_onChildChange (value) {
  136. // 更新子组件状态
  137. this.$_refreshChildState(value)
  138. /**
  139. * @event component:Segment#onChange
  140. * @description 子元素 样式更新后发送onChange事件,并传入value变化值
  141. * @property {string} value - 滚动事件对象
  142. */
  143. this.$emit('onChange', value)
  144. }
  145. }
  146. }
  147. </script>