add rate demo

pull/165/head
wangxueliang 2018-03-21 15:45:01 +08:00
parent 522627262b
commit de25852c95
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>
import '../style'
import { Rate, Icon } from 'antd/index'
import Basic from './basic.md'
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 {
category: 'Components',
subtitle: '评分',
type: 'Data Entry',
cols: 1,
title: 'Rate',
data () {
return {
allowHalf: true,
initValue: 3,
disabled: true,
hoverValue: undefined,
rValue: undefined,
hoverValueAH: undefined,
character: '好',
}
},
methods: {
onHoverChange (val) {
this.hoverValue = val
},
onChange (val) {
this.rValue = val
},
onHoverChangeAH (val) {
this.hoverValueAH = val
},
changeValue () {
this.initValue = 4
},
getValue () {
console.log(this.initValue)
},
},
components: {
Rate,
Icon,
render () {
return (
<div>
<md cn={md.cn} us={md.us}/>
<br/>
<Basic/>
<br/>
<Half/>
<br/>
<Text/>
<br/>
<Disabled/>
<br/>
<Clear/>
<br/>
<Character/>
<br/>
<api>
<template slot='cn'>
<CN/>
</template>
<US/>
</api>
</div>
)
},
}
</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 () {
const { onChange, onFocus } = this
const scopedSlots = (
<i class='anticon anticon-star' />
)
const rateProps = {
props: {
defaultValue: 2.5,
@ -30,9 +27,6 @@ export default {
style: {
fontSize: '50px', marginTop: '24px',
},
scopedSlots: {
character: scopedSlots,
},
}
const rateProps1 = {
props: {
@ -44,9 +38,6 @@ export default {
style: {
fontSize: '50px', marginTop: '24px',
},
scopedSlots: {
character: scopedSlots,
},
}
return (
<div style='margin: 100px'>
@ -72,11 +63,13 @@ export default {
<Rate
{...rateProps}
>
<i slot='character' class='anticon anticon-star' />
</Rate>
<br />
<Rate
{...rateProps1}
>
<i slot='character' class='anticon anticon-star' />
</Rate>
</div>
)

View File

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

View File

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

View File

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