add rate demo

pull/9/head
wangxueliang 2018-03-21 15:45:01 +08:00
parent f8b519ea6c
commit 9704271514
18 changed files with 320 additions and 325 deletions

View File

@ -1,138 +0,0 @@
import Star from './Star'
import Icon from '../icon'
import { getOffsetLeft } from './util'
import { cloneVNodes } from '../_util/vnode'
import hasProp from '../_util/props-util'
export default {
name: 'Rate',
props: {
prefixCls: {
type: String,
default: 'ant-rate',
},
count: {
type: Number,
default: 5,
},
value: Number,
defaultValue: {
type: Number,
default: 0,
},
allowHalf: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
character: {
type: String,
default: '★',
},
},
data () {
const { value, defaultValue } = this
const reValue = !hasProp(this, 'value') ? defaultValue : value
return {
hoverValue: undefined,
stateValue: reValue,
}
},
computed: {
classes () {
const { prefixCls, disabled } = this
return {
[`${prefixCls}`]: true,
[`${prefixCls}-disabled`]: disabled,
}
},
countList () {
return new Array(this.count).fill(1)
},
hasDefaultSlot () {
return !!this.$slots.default
},
},
methods: {
onClick (event, index) {
const value = this.getStarValue(index, event.pageX)
if (!hasProp(this, 'value')) {
this.stateValue = value
}
this.onMouseLeave()
this.$emit('input', value)
this.$emit('change', value)
},
onHover (event, index) {
const value = this.getStarValue(index, event.pageX)
this.hoverValue = value
this.$emit('hover-change', value)
},
getStarDOM (index) {
return this.$refs['stars' + index].$el
},
getStarValue (index, x) {
const { allowHalf, getStarDOM } = this
let value = index + 1
if (allowHalf) {
const leftEdge = getOffsetLeft(getStarDOM(0))
const width = getOffsetLeft(getStarDOM(1)) - leftEdge
if ((x - leftEdge - width * index) < width / 2) {
value -= 0.5
}
}
return value
},
onMouseLeave () {
if (this.disabled) return
this.hoverValue = undefined
this.$emit('hover-change')
},
},
watch: {
value (val) {
this.stateValue = val
},
},
components: {
Star,
Icon,
},
render (createElement) {
const {
classes, onMouseLeave, onClick, countList, onHover,
disabled, prefixCls, allowHalf, hoverValue,
stateValue, character, hasDefaultSlot,
} = this
return (
<ul
class={classes}
onMouseleave={onMouseLeave}>
{
countList.map((item, i) => {
return (
<Star
ref={'stars' + i}
index={i}
disabled={disabled}
prefixCls={`${prefixCls}-star`}
allowHalf={allowHalf}
value={hoverValue === undefined ? stateValue : hoverValue}
onClick={onClick}
onHover={onHover}
key={i}>
{(hasDefaultSlot) ? (cloneVNodes(this.$slots.default, true)) : character}
</Star>
)
})
}
</ul>
)
},
}

View File

@ -1,51 +0,0 @@
import { cloneVNodes } from '../_util/vnode'
export default {
name: 'Star',
props: {
index: Number,
disabled: Boolean,
prefixCls: String,
allowHalf: Boolean,
value: Number,
},
computed: {
getClassName () {
const { prefixCls, index, value, allowHalf } = this
const starValue = index + 1
if (allowHalf && value + 0.5 === starValue) {
return `${prefixCls} ${prefixCls}-half ${prefixCls}-active`
}
return starValue <= value ? `${prefixCls} ${prefixCls}-full` : `${prefixCls} ${prefixCls}-zero`
},
},
methods: {
onClick (e) {
if (this.disabled) return
this.$emit('click', e, this.index)
},
onHover (e) {
if (this.disabled) return
this.$emit('hover', e, this.index)
},
},
render (createElement) {
const { getClassName, onClick, onHover, prefixCls } = this
return (
<li
class={getClassName}
onClick={onClick}
onMousemove={onHover}
>
<div class={`${prefixCls}-first`}>
{this.$slots.default}
</div>
<div class={`${prefixCls}-second`}>
{cloneVNodes(this.$slots.default, true)}
</div>
</li>
)
},
}

View File

@ -0,0 +1,24 @@
<cn>
#### 基本
最简单的用法。
</cn>
<us>
#### Basic
The simplest usage.
</us>
```html
<template>
<a-rate v-model='value'/>
</template>
<script>
export default {
data() {
return {
value: 2,
}
},
}
</script>
```

View File

@ -0,0 +1,24 @@
<cn>
#### 其他字符
可以将星星替换为其他字符,比如字母,数字,字体图标甚至中文。
</cn>
<us>
#### Other Character
Replace the default star to other character like alphabet, digit, iconfont or even Chinese word.
</us>
```html
<template>
<div>
<a-rate allowHalf>
<a-icon slot="character" type="heart"/>
</a-rate>
<br />
<a-rate character="A" allowHalf style="fontSize: 36px"/>
<br />
<a-rate character="好" allowHalf/>
<br />
</div>
</template>
```

View File

@ -0,0 +1,20 @@
<cn>
#### 清除
支持允许或者禁用清除。
</cn>
<us>
#### Clear star
Support set allow to clear star when click again.
</us>
```html
<template>
<div>
<a-rate :defaultValue="3" /> allowClear: true
<br />
<a-rate :allowClear="false" :defaultValue="3" /> allowClear: false
<br />
</div>
</template>
```

View File

@ -0,0 +1,15 @@
<cn>
#### 只读
只读,无法进行鼠标交互。
</cn>
<us>
#### Read only
Read only, can't use mouse to interact.
</us>
```html
<template>
<a-rate :defaultValue="2" disabled />
</template>
```

View File

@ -0,0 +1,15 @@
<cn>
#### 半星
支持选中半星。
</cn>
<us>
#### Half star
Support select half star.
</us>
```html
<template>
<a-rate :defaultValue="2.5" allowHalf />
</template>
```

View File

@ -1,82 +1,65 @@
<template>
<div>
基本
<Rate class="custom"></Rate>
</br>
半星
<Rate :allowHalf="allowHalf"></Rate>
</br>
默认3颗星
<Rate v-model="initValue"></Rate>
<a-button type="primary" @click="changeValue"></a-button>
<a-button type="primary" @click="getValue"></a-button>
</br>
只读
<Rate :value="initValue" :disabled="disabled"></Rate>
</br>
回调函数
<Rate
@change="onChange"
@hover-change="onHoverChange"></Rate>
<span v-if="hoverValue">{{hoverValue}}stars</span>
<span v-if="rValue">{{rValue}}stars</span>
<br/>
<Rate
:allowHalf="allowHalf"
@hover-change="onHoverChangeAH"></Rate>
<span v-if="hoverValueAH">{{hoverValueAH}}stars</span>
</br>
自定义
</br>
<Rate v-model="initValue" :allowHalf="allowHalf">
<Icon type="heart" />
</Rate>
</br>
<Rate :defaultValue="initValue" :allowHalf="allowHalf" character="A"></Rate>
</br>
<Rate :value="initValue" character="好"></Rate>
</div>
</template>
<script> <script>
import '../style' import Basic from './basic.md'
import { Rate, Icon } from 'antd/index' import Half from './half.md'
import Text from './text.md'
import Disabled from './disabled.md'
import Clear from './clear.md'
import Character from './character.md'
import CN from '../index.zh-CN.md'
import US from '../index.en-US.md'
const md = {
cn: `# Rate
评分组件
## 何时使用
- 对评价进行展示
- 对事物进行快速的评级操作
## 代码演示`,
us: `# Rate
Rate component.
# When To Use
- Show evaluation.
- A quick rating operation on something.
## Examples
`,
}
export default { export default {
category: 'Components', category: 'Components',
subtitle: '评分', subtitle: '评分',
type: 'Data Entry', type: 'Data Entry',
cols: 1,
title: 'Rate', title: 'Rate',
data () { render () {
return { return (
allowHalf: true, <div>
initValue: 3, <md cn={md.cn} us={md.us}/>
disabled: true, <br/>
hoverValue: undefined, <Basic/>
rValue: undefined, <br/>
hoverValueAH: undefined, <Half/>
character: '好', <br/>
} <Text/>
}, <br/>
methods: { <Disabled/>
onHoverChange (val) { <br/>
this.hoverValue = val <Clear/>
}, <br/>
onChange (val) { <Character/>
this.rValue = val <br/>
}, <api>
onHoverChangeAH (val) { <template slot='cn'>
this.hoverValueAH = val <CN/>
}, </template>
changeValue () { <US/>
this.initValue = 4 </api>
}, </div>
getValue () { )
console.log(this.initValue)
},
},
components: {
Rate,
Icon,
}, },
} }
</script> </script>

View File

@ -0,0 +1,27 @@
<cn>
#### 文案展现
给评分组件加上文案展示。
</cn>
<us>
#### Show copywriting
Add copywriting in rate components.
</us>
```html
<template>
<span>
<a-rate v-model='value'/>
<span class="ant-rate-text">{{value}} stars</span>
</span>
</template>
<script>
export default {
data() {
return {
value: 3,
}
},
}
</script>
```

View File

@ -0,0 +1,29 @@
## API
| Property | Description | type | Default |
| -------- | ----------- | ---- | ------- |
| allowClear | whether to allow clear when click again | boolean | true |
| allowHalf | whether to allow semi selection | boolean | false |
| autoFocus | get focus when component mounted | boolean | false |
| character | custom character of rate | String or slot="character" | `<Icon type="star" />` |
| count | star count | number | 5 |
| defaultValue | default value | number | 0 |
| disabled | read only, unable to interact | boolean | false |
| value(v-model) | current value | number | - |
### events
| Events Name | Description | Arguments |
| --- | --- | --- |
| blur | callback when component lose focus | Function() | - |
| change | callback when select value | Function(value: number) | - |
| focus | callback when component get focus | Function() | - |
| hoverChange | callback when hover item | Function(value: number) | - |
| keydown | callback when keydown on component | Function(event) | - |
## Methods
| Name | Description |
| ---- | ----------- |
| blur() | remove focus |
| focus() | get focus |

View File

@ -1,3 +0,0 @@
import Rate from './Rate'
export default Rate

61
components/rate/index.jsx Normal file
View File

@ -0,0 +1,61 @@
import PropTypes from '../_util/vue-types'
import { initDefaultProps, getOptionProps } from '../_util/props-util'
import VcRate from '../vc-rate'
import Icon from '../icon'
export const RateProps = {
prefixCls: PropTypes.string,
count: PropTypes.number,
value: PropTypes.value,
defaultValue: PropTypes.value,
allowHalf: PropTypes.bool,
allowClear: PropTypes.bool,
disabled: PropTypes.bool,
hoverChange: PropTypes.func,
character: PropTypes.any,
}
export default {
name: 'Rate',
model: {
prop: 'value',
event: 'change',
},
props: initDefaultProps(RateProps, {
prefixCls: 'ant-rate',
}),
methods: {
focus () {
this.$refs.refRate.focus()
},
blur () {
this.$refs.refRate.blur()
},
},
render () {
const { character, ...restProps } = getOptionProps(this)
const slotCharacter = this.$slots.character
const rateProps = {
props: {
character,
...restProps,
},
on: this.$listeners,
ref: 'refRate',
}
const slotCharacterHtml = slotCharacter !== undefined ? (
<template slot='character'>{slotCharacter}</template>
) : <Icon slot='character' type='star' />
return (
<VcRate
{...rateProps}
>
{
character === undefined ? slotCharacterHtml : null
}
</VcRate>
)
},
}

View File

@ -0,0 +1,28 @@
## API
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| allowClear | 是否允许再次点击后清除 | boolean | true |
| allowHalf | 是否允许半选 | boolean | false |
| autoFocus | 自动获取焦点 | boolean | false |
| character | 自定义字符 | String or slot="character" | `<Icon type="star" />` |
| count | star 总数 | number | 5 |
| defaultValue | 默认值 | number | 0 |
| disabled | 只读,无法进行交互 | boolean | false |
| value(v-model) | 当前数,受控值 | number | - |
### 事件
| 事件名称 | 说明 | 回调参数 |
| --- | --- | --- |
| blur | 失去焦点时的回调 | Function() | - |
| change | 选择时的回调 | Function(value: number) | - |
| focus | 获取焦点时的回调 | Function() | - |
| hoverChange | 鼠标经过时数值变化的回调 | Function(value: number) | - |
| keydown | 按键回调 | Function(event) | - |
## 方法
| 名称 | 描述 |
| --- | --- |
| blur() | 移除焦点 |
| focus() | 获取焦点 |

View File

@ -1,39 +0,0 @@
function getScroll (w, top) {
let ret = top ? w.pageYOffset : w.pageXOffset
const method = top ? 'scrollTop' : 'scrollLeft'
if (typeof ret !== 'number') {
const d = w.document
// ie6,7,8 standard mode
ret = d.documentElement[method]
if (typeof ret !== 'number') {
// quirks mode
ret = d.body[method]
}
}
return ret
}
function getClientPosition (elem) {
let x
let y
const doc = elem.ownerDocument
const body = doc.body
const docElem = doc && doc.documentElement
const box = elem.getBoundingClientRect()
x = box.left
y = box.top
x -= docElem.clientLeft || body.clientLeft || 0
y -= docElem.clientTop || body.clientTop || 0
return {
left: x,
top: y,
}
}
export function getOffsetLeft (el) {
const pos = getClientPosition(el)
const doc = el.ownerDocument
const w = doc.defaultView || doc.parentWindow
pos.left += getScroll(w)
return pos.left
}

View File

@ -16,9 +16,6 @@ export default {
}, },
render () { render () {
const { onChange, onFocus } = this const { onChange, onFocus } = this
const scopedSlots = (
<i class='anticon anticon-star' />
)
const rateProps = { const rateProps = {
props: { props: {
defaultValue: 2.5, defaultValue: 2.5,
@ -30,9 +27,6 @@ export default {
style: { style: {
fontSize: '50px', marginTop: '24px', fontSize: '50px', marginTop: '24px',
}, },
scopedSlots: {
character: scopedSlots,
},
} }
const rateProps1 = { const rateProps1 = {
props: { props: {
@ -44,9 +38,6 @@ export default {
style: { style: {
fontSize: '50px', marginTop: '24px', fontSize: '50px', marginTop: '24px',
}, },
scopedSlots: {
character: scopedSlots,
},
} }
return ( return (
<div style='margin: 100px'> <div style='margin: 100px'>
@ -72,11 +63,13 @@ export default {
<Rate <Rate
{...rateProps} {...rateProps}
> >
<i slot='character' class='anticon anticon-star' />
</Rate> </Rate>
<br /> <br />
<Rate <Rate
{...rateProps1} {...rateProps1}
> >
<i slot='character' class='anticon anticon-star' />
</Rate> </Rate>
</div> </div>
) )

View File

@ -19,6 +19,8 @@ const rateProps = {
autoFocus: PropTypes.bool, autoFocus: PropTypes.bool,
} }
function noop () {}
export default { export default {
name: 'Rate', name: 'Rate',
mixins: [BaseMixin], mixins: [BaseMixin],
@ -31,7 +33,7 @@ export default {
tabIndex: 0, tabIndex: 0,
character: '★', character: '★',
}), }),
modal: { model: {
prop: 'value', prop: 'value',
event: 'change', event: 'change',
}, },
@ -173,7 +175,7 @@ export default {
const { sValue, hoverValue, focused } = this const { sValue, hoverValue, focused } = this
const stars = [] const stars = []
const disabledClass = disabled ? `${prefixCls}-disabled` : '' const disabledClass = disabled ? `${prefixCls}-disabled` : ''
const slotCharacter = this.$scopedSlots.character const slotCharacter = this.$slots.character
for (let index = 0; index < count; index++) { for (let index = 0; index < count; index++) {
const starProps = { const starProps = {
props: { props: {
@ -191,22 +193,25 @@ export default {
}, },
key: index, key: index,
ref: `stars${index}`, ref: `stars${index}`,
scopedSlots: this.$scopedSlots,
} }
stars.push( stars.push(
<Star <Star
{...starProps} {...starProps}
/> >
{
slotCharacter !== undefined ? (<template slot='character'>{slotCharacter}</template>) : null
}
</Star>
) )
} }
return ( return (
<ul <ul
class={classNames(prefixCls, disabledClass)} class={classNames(prefixCls, disabledClass)}
onMouseleave={disabled ? null : this.onMouseLeave} onMouseleave={disabled ? noop : this.onMouseLeave}
tabIndex={disabled ? -1 : tabIndex} tabIndex={disabled ? -1 : tabIndex}
onFocus={disabled ? null : this.onFocus} onFocus={disabled ? noop : this.onFocus}
onBlur={disabled ? null : this.onBlur} onBlur={disabled ? noop : this.onBlur}
onKeydown={disabled ? null : this.onKeyDown} onKeydown={disabled ? noop : this.onKeyDown}
ref='rateRef' ref='rateRef'
> >
{stars} {stars}

View File

@ -1,5 +1,7 @@
import PropTypes from '../../_util/vue-types' import PropTypes from '../../_util/vue-types'
function noop () {}
export default { export default {
name: 'Star', name: 'Star',
props: { props: {
@ -44,13 +46,13 @@ export default {
const { onHover, onClick, disabled, prefixCls } = this const { onHover, onClick, disabled, prefixCls } = this
let character = this.character let character = this.character
if (character === undefined) { if (character === undefined) {
character = this.$scopedSlots.character character = this.$slots.character
} }
return ( return (
<li <li
class={this.getClassName()} class={this.getClassName()}
onClick={disabled ? null : onClick} onClick={disabled ? noop : onClick}
onMousemove={disabled ? null : onHover} onMousemove={disabled ? noop : onHover}
> >
<div class={`${prefixCls}-first`}>{character}</div> <div class={`${prefixCls}-first`}>{character}</div>
<div class={`${prefixCls}-second`}>{character}</div> <div class={`${prefixCls}-second`}>{character}</div>

View File

@ -3,7 +3,7 @@ const AsyncComp = () => {
const hashs = window.location.hash.split('/') const hashs = window.location.hash.split('/')
const d = hashs[hashs.length - 1] const d = hashs[hashs.length - 1]
return { return {
component: import(`../components/vc-rate/demo/${d}`), component: import(`../components/rate/demo/${d}`),
} }
} }
export default [ export default [