[new feature] Radio: 增加单选框组件 (#629)

This commit is contained in:
rex 2018-09-23 14:57:20 +08:00 committed by neverland
parent 51f7adacfa
commit 23ebe64fd1
15 changed files with 394 additions and 1 deletions

View File

@ -30,7 +30,8 @@
"pages/transition/index",
"pages/tree-select/index",
"pages/area/index",
"pages/submit-bar/index"
"pages/submit-bar/index",
"pages/radio/index"
],
"window": {
"navigationBarBackgroundColor": "#f8f8f8",

View File

@ -75,6 +75,10 @@ export default [
path: '/field',
title: 'Field 输入框'
},
{
path: '/radio',
title: 'Radio 单选框'
},
{
path: '/search',
title: 'Search 搜索'

View File

@ -0,0 +1,21 @@
import Page from '../../common/page';
Page({
data: {
radio1: '1',
radio2: '2',
radio3: '1'
},
onChange(event) {
const { key } = event.currentTarget.dataset;
this.setData({ [key]: event.detail });
},
onClick(event) {
const { value } = event.currentTarget.dataset;
this.setData({
radio3: value
});
}
});

View File

@ -0,0 +1,10 @@
{
"navigationBarTitleText": "Search 搜索",
"usingComponents": {
"demo-block": "../../components/demo-block/index",
"van-radio-group": "../../dist/radio-group/index",
"van-cell-group": "../../dist/cell-group/index",
"van-cell": "../../dist/cell/index",
"van-radio": "../../dist/radio/index"
}
}

View File

@ -0,0 +1,26 @@
<demo-block title="基本用法">
<van-radio-group value="{{ radio1 }}" data-key="radio1" bind:change="onChange" custom-class="demo-radio-group">
<van-radio name="1" custom-class="demo-radio">单选框 1</van-radio>
<van-radio name="2" custom-class="demo-radio">单选框 2</van-radio>
</van-radio-group>
</demo-block>
<demo-block title="禁用状态">
<van-radio-group value="{{ radio2 }}" data-key="radio2" bind:change="onChange" disabled custom-class="demo-radio-group">
<van-radio name="1" custom-class="demo-radio">单选框 1</van-radio>
<van-radio name="2" custom-class="demo-radio">单选框 2</van-radio>
</van-radio-group>
</demo-block>
<demo-block title="与 Cell 组件一起使用">
<van-radio-group value="{{ radio3 }}">
<van-cell-group>
<van-cell title="单选框 1" clickable data-value="1" bind:click="onClick">
<van-radio name="1" />
</van-cell>
<van-cell title="单选框 2" clickable data-value="2" bind:click="onClick">
<van-radio name="2" />
</van-cell>
</van-cell-group>
</van-radio-group>
</demo-block>

View File

@ -0,0 +1,7 @@
.demo-radio-group {
padding: 0 17px;
}
.demo-radio {
margin-bottom: 10px;
}

View File

@ -0,0 +1,37 @@
import { create } from '../common/create';
create({
relations: {
'../radio/index': {
type: 'descendant',
linked(target) {
const { value, disabled } = this.data;
target.setData({
value: value,
disabled: disabled || target.data.disabled
});
}
}
},
props: {
value: {
type: null,
observer(value) {
const children = this.getRelationNodes('../radio/index');
children.forEach(child => {
child.setData({ value });
});
}
},
disabled: {
type: Boolean,
observer(disabled) {
const children = this.getRelationNodes('../radio/index');
children.forEach(child => {
child.setData({ disabled: disabled || children.data.disabled });
});
}
}
}
});

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index"
}
}

View File

@ -0,0 +1,55 @@
@import '../common/style/var.pcss';
$van-radio-size: 20px;
.van-radio {
overflow: hidden;
user-select: none;
&__input,
&__label {
display: inline-block;
vertical-align: middle;
}
&__input {
height: 1em;
position: relative;
font-size: $van-radio-size;
}
&__control {
z-index: 1;
position: absolute;
top: 0;
left: 0;
opacity: 0;
margin: 0;
width: 100%;
height: 100%;
}
&__label {
line-height: $van-radio-size;
margin-left: 10px;
&--left {
float: left;
margin: 0 10px 0 0;
}
}
&__icon {
width: 1em;
pointer-events: none;
&--disabled {
color: $gray-light;
}
&--checked {
color: $green;
}
&--check {
color: $gray-dark;
}
}
}

View File

@ -0,0 +1,3 @@
<view class="custom-class">
<slot />
</view>

91
packages/radio/README.md Normal file
View File

@ -0,0 +1,91 @@
## Radio 单选框
### 使用指南
在 index.json 中引入组件
```json
"usingComponents": {
"van-radio": "path/to/vant-weapp/dist/radio/index",
"van-radio-group": "path/to/vant-weapp/dist/radio-group/index"
}
```
### 代码演示
#### 基础用法
通过`value`绑定值当前选中项的 name
```html
<van-radio-group value="{{ radio }}" bind:change="onChange">
<van-radio name="1">单选框 1</van-radio>
<van-radio name="2">单选框 2</van-radio>
</van-radio-group>
```
#### 禁用状态
通过`disabled`属性禁止选项切换,在`van-radio`上设置`diabled`可以禁用单个选项
```html
<van-radio-group value="{{ radio }}" bind:change="onChange" disabled>
<van-radio name="1">单选框 1</van-radio>
<van-radio name="2">单选框 2</van-radio>
</van-radio-group>
```
#### 与 Cell 组件一起使用
此时你需要再引入`Cell``CellGroup`组件。
```html
<van-radio-group value="{{ radio }}" bind:change="onChange">
<van-cell-group>
<van-cell title="单选框 1" clickable data-name="1" bind:click="onClick">
<van-radio name="1" />
</van-cell>
<van-cell title="单选框 2" clickable data-name="2" bind:click="onClick">
<van-radio name="2" />
</van-cell>
</van-cell-group>
</van-radio-group>
```
### Radio API
| 参数 | 说明 | 类型 | 默认值 |
|-----------|-----------|-----------|-------------|
| name | 标识 Radio 名称 | 任意类型 | - |
| value | 当前选中项的 name | 任意类型 | - |
| disabled | 是否为禁用状态 | `Boolean` | `false` |
| label-disabled | 是否禁用文本内容点击 | `Boolean` | `false` |
| label-position | 文本位置,可选值为 `left` | `String` | `right` |
### Radio Event
| 事件名称 | 说明 | 回调参数 |
|-----------|-----------|-----------|
| change | 当绑定值变化时触发的事件 | 当前选中项的 name |
### Radio 外部样式类
| 类名 | 说明 |
|-----------|-----------|
| custom-class | 根节点样式类 |
| icon-class | 图标样式类 |
| label-class | 描述信息样式类 |
### RadioGroup API
| 参数 | 说明 | 类型 | 默认值 |
|-----------|-----------|-----------|-------------|
| value | 当前选中项的 name | 任意类型 | - |
| disabled | 是否禁用所有单选框 | `Boolean` | `false` |
### RadioGroup Event
| 事件名称 | 说明 | 回调参数 |
|-----------|-----------|-----------|
| change | 当绑定值变化时触发的事件 | 当前选中项的 name |
### RadioGroup 外部样式类
| 类名 | 说明 |
|-----------|-----------|
| custom-class | 根节点样式类 |

49
packages/radio/index.js Normal file
View File

@ -0,0 +1,49 @@
import { create } from '../common/create';
create({
relations: {
'../radio-group/index': {
type: 'ancestor'
}
},
classes: ['icon-class', 'label-class'],
props: {
name: null,
value: null,
disabled: Boolean,
labelDisabled: Boolean,
labelPosition: String
},
computed: {
iconClass() {
const { disabled, name, value } = this.data;
return this.classNames('van-radio__icon', {
'van-radio__icon--disabled': disabled,
'van-radio__icon--checked': !disabled && name === value,
'van-radio__icon--check': !disabled && name !== value
});
}
},
methods: {
emitChange(value) {
const parent = this.getRelationNodes('../radio-group/index')[0];
(parent || this).$emit('input', value);
(parent || this).$emit('change', value);
},
onChange(event) {
const { value } = event.detail;
this.emitChange(value);
},
onClickLabel() {
if (!this.data.disabled && !this.data.labelDisabled) {
this.emitChange(this.data.name);
}
}
}
});

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index"
}
}

61
packages/radio/index.pcss Normal file
View File

@ -0,0 +1,61 @@
@import '../common/style/var.pcss';
$van-radio-size: 20px;
.van-radio {
overflow: hidden;
line-height: 1;
user-select: none;
&__input,
&__label {
display: inline-block;
vertical-align: middle;
}
&__input {
position: relative;
font-size: $van-radio-size;
}
&__control {
z-index: 1;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
}
&__label {
margin-left: 10px;
color: $text-color;
font-size: 16px;
line-height: $van-radio-size;
&--left {
margin: 0 10px 0 0;
float: left;
}
}
&__icon {
pointer-events: none;
display: block;
line-height: 0;
&--disabled {
color: $gray-light;
}
&--checked {
color: $green;
}
&--check {
color: $gray-dark;
}
}
}

16
packages/radio/index.wxml Normal file
View File

@ -0,0 +1,16 @@
<view class="van-radio custom-class">
<view class="van-radio__input">
<radio-group bindchange="onChange">
<radio
value="{{ name }}"
checked="{{ value === name }}"
disabled="{{ disabled }}"
class="van-radio__control"
/>
</radio-group>
<van-icon class="{{ iconClass }}" custom-class="icon-class" name="{{ value === name ? 'checked' : 'check' }}" />
</view>
<view class="van-radio__label van-radio__label--{{ labelPosition }} label-class" bindtap="onClickLabel">
<slot />
</view>
</view>