From 6abbb0b3164d13a943dae8d891f95ff4b09ad934 Mon Sep 17 00:00:00 2001 From: rex Date: Fri, 28 Sep 2018 16:58:55 +0800 Subject: [PATCH] =?UTF-8?q?[new=20feature]=20Checkbox:=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=A4=8D=E9=80=89=E6=A1=86=E7=BB=84=E4=BB=B6=20(#666)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/src/Preview.vue | 3 +- example/app.json | 3 +- example/config.js | 4 + example/pages/checkbox/index.js | 36 ++++++ example/pages/checkbox/index.json | 10 ++ example/pages/checkbox/index.wxml | 58 +++++++++ example/pages/checkbox/index.wxss | 11 ++ packages/checkbox-group/index.json | 6 + packages/checkbox-group/index.less | 0 packages/checkbox-group/index.ts | 37 ++++++ packages/checkbox-group/index.wxml | 3 + packages/checkbox/README.md | 190 +++++++++++++++++++++++++++++ packages/checkbox/index.json | 6 + packages/checkbox/index.less | 56 +++++++++ packages/checkbox/index.ts | 77 ++++++++++++ packages/checkbox/index.wxml | 9 ++ packages/radio-group/index.less | 55 --------- 17 files changed, 507 insertions(+), 57 deletions(-) create mode 100644 example/pages/checkbox/index.js create mode 100644 example/pages/checkbox/index.json create mode 100644 example/pages/checkbox/index.wxml create mode 100644 example/pages/checkbox/index.wxss create mode 100644 packages/checkbox-group/index.json create mode 100644 packages/checkbox-group/index.less create mode 100644 packages/checkbox-group/index.ts create mode 100644 packages/checkbox-group/index.wxml create mode 100644 packages/checkbox/README.md create mode 100644 packages/checkbox/index.json create mode 100644 packages/checkbox/index.less create mode 100644 packages/checkbox/index.ts create mode 100644 packages/checkbox/index.wxml diff --git a/docs/src/Preview.vue b/docs/src/Preview.vue index 903e23a4..582d8e7f 100644 --- a/docs/src/Preview.vue +++ b/docs/src/Preview.vue @@ -44,7 +44,8 @@ const MAP = { tabbar: 'tabbar-201808160922.png', toast: 'toast-201808191046.png', transition: 'transition-20180821.png', - 'tree-select': 'tree-select-201808092138.png' + 'tree-select': 'tree-select-201808092138.png', + checkbox: 'checkbox-20180928-1.png' }; export default { diff --git a/example/app.json b/example/app.json index 3b75d79f..bea9f296 100644 --- a/example/app.json +++ b/example/app.json @@ -31,7 +31,8 @@ "pages/tree-select/index", "pages/area/index", "pages/submit-bar/index", - "pages/radio/index" + "pages/radio/index", + "pages/checkbox/index" ], "window": { "navigationBarBackgroundColor": "#f8f8f8", diff --git a/example/config.js b/example/config.js index f215eaaf..4d3cb92f 100644 --- a/example/config.js +++ b/example/config.js @@ -71,6 +71,10 @@ export default [ { groupName: '表单组件', list: [ + { + path: '/checkbox', + title: 'Checkbox 复选框' + }, { path: '/field', title: 'Field 输入框' diff --git a/example/pages/checkbox/index.js b/example/pages/checkbox/index.js new file mode 100644 index 00000000..7ff0a2fd --- /dev/null +++ b/example/pages/checkbox/index.js @@ -0,0 +1,36 @@ +import Page from '../../common/page'; + +Page({ + data: { + checkbox1: true, + checkbox2: true, + list: ['a', 'b', 'c'], + result: ['a', 'b'], + result2: [], + result3: [], + icon: { + normal: + 'https://img.yzcdn.cn/public_files/2017/10/13/c547715be149dd3faa817e4a948b40c4.png', + active: + 'https://img.yzcdn.cn/public_files/2017/10/13/793c77793db8641c4c325b7f25bf130d.png' + } + }, + + onChange(event) { + const { key } = event.currentTarget.dataset; + this.setData({ [key]: event.detail }); + }, + + onClick(event) { + const { value } = event.currentTarget.dataset; + this.setData({ + radio3: value + }); + }, + + toggle(event) { + const { name } = event.currentTarget.dataset; + const checkbox = this.selectComponent(`.checkboxes-${name}`); + checkbox.toggle(); + } +}); diff --git a/example/pages/checkbox/index.json b/example/pages/checkbox/index.json new file mode 100644 index 00000000..8b2d8481 --- /dev/null +++ b/example/pages/checkbox/index.json @@ -0,0 +1,10 @@ +{ + "navigationBarTitleText": "Checkbox 复选框", + "usingComponents": { + "demo-block": "../../components/demo-block/index", + "van-checkbox-group": "../../dist/checkbox-group/index", + "van-checkbox": "../../dist/checkbox/index", + "van-cell": "../../dist/cell/index", + "van-cell-group": "../../dist/cell-group/index" + } +} diff --git a/example/pages/checkbox/index.wxml b/example/pages/checkbox/index.wxml new file mode 100644 index 00000000..8102a8be --- /dev/null +++ b/example/pages/checkbox/index.wxml @@ -0,0 +1,58 @@ + + 复选框 + + + + 复选框 + 复选框 + + + + + 自定义图标 + + + + + + + + 复选框 {{ item }} + + + + + + + + 复选框 {{ item }} + + + + + + + + + + + + + diff --git a/example/pages/checkbox/index.wxss b/example/pages/checkbox/index.wxss new file mode 100644 index 00000000..4ed6d7b4 --- /dev/null +++ b/example/pages/checkbox/index.wxss @@ -0,0 +1,11 @@ +.demo-checkbox-group { + margin: 10px 0 0 20px; +} + +.demo-checkbox { + margin: 10px 0 0 20px; +} + +.icon { + width: 20px; +} diff --git a/packages/checkbox-group/index.json b/packages/checkbox-group/index.json new file mode 100644 index 00000000..0a336c08 --- /dev/null +++ b/packages/checkbox-group/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "van-icon": "../icon/index" + } +} diff --git a/packages/checkbox-group/index.less b/packages/checkbox-group/index.less new file mode 100644 index 00000000..e69de29b diff --git a/packages/checkbox-group/index.ts b/packages/checkbox-group/index.ts new file mode 100644 index 00000000..ef6a3f53 --- /dev/null +++ b/packages/checkbox-group/index.ts @@ -0,0 +1,37 @@ +import { VantComponent } from '../common/component'; + +VantComponent({ + relation: { + name: 'checkbox', + type: 'descendant', + linked(target: Weapp.Component) { + const { value, disabled } = this.data; + target.setData({ + value: value.indexOf(target.data.name) !== -1, + disabled: disabled || target.data.disabled + }); + } + }, + + props: { + value: Array, + disabled: Boolean, + max: Number + }, + + watch: { + value(value) { + const children = this.getRelationNodes('../checkbox/index'); + children.forEach(child => { + child.setData({ value: value.indexOf(child.data.name) !== -1 }); + }); + }, + + disabled(disabled: boolean) { + const children = this.getRelationNodes('../checkbox/index'); + children.forEach(child => { + child.setData({ disabled: disabled || child.data.disabled }); + }); + } + } +}); diff --git a/packages/checkbox-group/index.wxml b/packages/checkbox-group/index.wxml new file mode 100644 index 00000000..775ee3ce --- /dev/null +++ b/packages/checkbox-group/index.wxml @@ -0,0 +1,3 @@ + + + diff --git a/packages/checkbox/README.md b/packages/checkbox/README.md new file mode 100644 index 00000000..c0baceea --- /dev/null +++ b/packages/checkbox/README.md @@ -0,0 +1,190 @@ +## Checkbox 复选框 + +### 使用指南 +在 index.json 中引入组件 +```json +"usingComponents": { + "van-checkbox": "path/to/vant-weapp/dist/checkbox/index", + "van-checkbox-group": "path/to/vant-weapp/dist/checkbox-group/index" +} +``` + +### 代码演示 + +#### 基础用法 +通过`value`绑定 checkbox 的勾选状态 + +```html +复选框 +``` + +#### 禁用状态 + +```html +复选框 +``` + +#### 自定义图标 +通过 icon 插槽自定义图标 + +```html + + 自定义图标 + + +``` + +```js +Page({ + data: { + checked: true, + icon: { + normal: '//img.yzcdn.cn/icon-normal.png', + active: '//img.yzcdn.cn/icon-active.png' + } + }, + + onChange(event) { + this.setData({ + checked: event.detail + }); + } +}); +``` + +#### Checkbox 组 + +需要与`van-checkbox-group`一起使用,选中值是一个数组,通过`value`绑定在`van-checkbox-group`上,数组中的项即为选中的`Checkbox`的`name`属性设置的值 + +```html + + + 复选框 {{ item }} + + +``` + +```javascript +Page({ + data: { + list: ['a', 'b', 'c'], + result: ['a', 'b'] + }, + + onChange(event) { + this.setData({ + result: event.detail + }); + } +}); +``` + +#### 设置最大可选数 + +```html + + + 复选框 {{ item }} + + +``` + +#### 与 Cell 组件一起使用 + +此时你需要再引入`Cell`和`CellGroup`组件,并通过 checkbox 的 toggle 方法手动触发切换 + +```html + + + + + + + +``` + +```js +Page({ + data: { + list: ['a', 'b', 'c'], + result: ['a', 'b'] + }, + + onChange(event) { + this.setData({ + result: event.detail + }); + } + + toggle(event) { + const { name } = event.currentTarget.dataset; + const checkbox = this.selectComponent(`.checkboxes-${name}`); + checkbox.toggle(); + } +}); +``` + +### Checkbox API + +| 参数 | 说明 | 类型 | 默认值 | +|-----------|-----------|-----------|-------------| +| name | 标识 Checkbox 名称 | `any` | - | +| value | 是否为选中状态 | `Boolean` | `false` | +| disabled | 是否禁用单选框 | `Boolean` | `false` | +| label-disabled | 是否禁用单选框内容点击 | `Boolean` | `false` | +| label-position | 文本位置,可选值为 `left` | `String` | `right` | +| shape | 形状,可选值为 `round` `square` | `String` | `round` | +| use-icon-slot | 是否使用 icon slot | `Boolean` | `false` | + +### CheckboxGroup API + +| 参数 | 说明 | 类型 | 默认值 | +|-----------|-----------|-----------|-------------| +| value | 所有选中项的 name | `Array` | - | +| disabled | 是否禁用所有单选框 | `Boolean` | `false` | +| max | 设置最大可选数 | `Number` | `0`(无限制) | + +### Checkbox Event + +| 事件名称 | 说明 | 回调参数 | +|-----------|-----------|-----------| +| change | 当绑定值变化时触发的事件 | 当前组件的值 | + +### CheckboxGroup Event + +| 事件名称 | 说明 | 回调参数 | +|-----------|-----------|-----------| +| change | 当绑定值变化时触发的事件 | 当前组件的值 | + +### Checkbox Slot + +| 名称 | 说明 | slot-scope | +|-----------|-----------|-----------| +| - | 自定义文本 | - | +| icon | 自定义图标 | checked: 是否为选中状态 | + +### Checkbox 方法 + +通过 selectComponent 可以获取到 checkbox 实例并调用实例方法 + +| 方法名 | 参数 | 返回值 | 介绍 | +|-----------|-----------|-----------|-------------| +| toggle | - | - | 切换选中状态 | diff --git a/packages/checkbox/index.json b/packages/checkbox/index.json new file mode 100644 index 00000000..0a336c08 --- /dev/null +++ b/packages/checkbox/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "van-icon": "../icon/index" + } +} diff --git a/packages/checkbox/index.less b/packages/checkbox/index.less new file mode 100644 index 00000000..de3e18fe --- /dev/null +++ b/packages/checkbox/index.less @@ -0,0 +1,56 @@ +@import '../common/style/var.less'; + +@van-checkbox-size: 20px; + +.van-checkbox { + overflow: hidden; + user-select: none; + + &__icon-wrap, + &__label { + display: inline-block; + line-height: @van-checkbox-size; + vertical-align: middle; + } + + &__icon { + box-sizing: border-box; + display: block; + width: @van-checkbox-size; + height: @van-checkbox-size; + border: 1px solid #aaa; + color: transparent; + font-size: 12px; + text-align: center; + + &--round { + border-radius: 100%; + } + + &--checked { + border-color: @green; + background-color: @green; + color: #fff; + } + + &--disabled { + border-color: @border-color; + background-color: currentColor; + color: @background-color; + } + + &--disabled&--checked { + border-color: @border-color; + background-color: @border-color; + } + } + + &__label { + margin-left: 10px; + + &--left { + margin: 0 10px 0 0; + float: left; + } + } +} diff --git a/packages/checkbox/index.ts b/packages/checkbox/index.ts new file mode 100644 index 00000000..996394a7 --- /dev/null +++ b/packages/checkbox/index.ts @@ -0,0 +1,77 @@ +import { VantComponent } from '../common/component'; + +VantComponent({ + relation: { + name: 'checkbox-group', + type: 'ancestor' + }, + + classes: ['icon-class', 'label-class'], + + props: { + name: null, + value: null, + disabled: Boolean, + labelDisabled: Boolean, + labelPosition: String, + shape: { + type: String, + value: 'round' + }, + useIconSlot: Boolean + }, + + computed: { + iconClass(): string { + const { disabled, value, shape } = this.data; + return this.classNames('van-checkbox__icon', `van-checkbox__icon--${shape}`, { + 'van-checkbox__icon--disabled': disabled, + 'van-checkbox__icon--checked': value + }); + } + }, + + methods: { + emitChange(value) { + const parent = this.getRelationNodes('../checkbox-group/index')[0]; + if (parent) { + const parentValue = parent.data.value.slice(); + const { name } = this.data; + if (value) { + if (parent.data.max && parentValue.length >= parent.data.max) { + return; + } + /* istanbul ignore else */ + if (parentValue.indexOf(name) === -1) { + parentValue.push(name); + parent.$emit('input', parentValue); + parent.$emit('change', parentValue); + } + } else { + const index = parentValue.indexOf(name); + /* istanbul ignore else */ + if (index !== -1) { + parentValue.splice(index, 1); + parent.$emit('input', parentValue); + parent.$emit('change', parentValue); + } + } + } else { + this.$emit('input', value); + this.$emit('change', value); + } + }, + + toggle() { + if (!this.data.disabled) { + this.emitChange(!this.data.value); + } + }, + + onClickLabel() { + if (!this.data.disabled && !this.data.labelDisabled) { + this.emitChange(!this.data.value); + } + } + } +}); diff --git a/packages/checkbox/index.wxml b/packages/checkbox/index.wxml new file mode 100644 index 00000000..d320d0f3 --- /dev/null +++ b/packages/checkbox/index.wxml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/radio-group/index.less b/packages/radio-group/index.less index ae41f459..e69de29b 100644 --- a/packages/radio-group/index.less +++ b/packages/radio-group/index.less @@ -1,55 +0,0 @@ -@import '../common/style/var.less'; - -@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; - } - } -}