feat(radio): refresh radio UI (#845)

* feat(radio): 刷新设计规范

Signed-off-by: jacknan <zhumaonan@aliyun.com>

* feat(radio): 刷新设计规范

Signed-off-by: jacknan <zhumaonan@aliyun.com>

* feat(radio): 拆分特性demo

Signed-off-by: jacknan <zhumaonan@aliyun.com>

* feat(radio): 刷新token定义,添加注释

Signed-off-by: jacknan <zhumaonan@aliyun.com>

* feat(radio): 优化demo

Signed-off-by: jacknan <zhumaonan@aliyun.com>

---------

Signed-off-by: jacknan <zhumaonan@aliyun.com>
This commit is contained in:
jacknan 2023-11-22 15:17:19 +08:00 committed by GitHub
parent 16066bd9fd
commit 91dd24ec46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 205 additions and 276 deletions

View File

@ -1,87 +1,20 @@
<template>
<div class="demo">
<p class="demo-title">勾选-单选</p>
<div>
<tiny-list
class="demo-list"
v-for="item of dataList"
:key="item.id"
:id="item.id"
:content="item.content"
:sub-text="item.subtext"
@click="clickFn"
>
<template #suffix>
<tiny-radio v-model="value1" :label="item.id"></tiny-radio>
</template>
</tiny-list>
</div>
<div class="withlist">
<tiny-list
class="demo-list"
v-for="item of dataList1"
:key="item.id"
:id="item.id"
:content="item.content"
:sub-text="item.subtext"
:content-des="item.contentdes"
@click="clickFn"
>
<template #suffix>
<tiny-radio v-model="value1" :label="item.id"></tiny-radio>
</template>
</tiny-list>
</div>
<p>默认</p>
<tiny-radio v-model="value"></tiny-radio>
</div>
</template>
<script lang="jsx">
import { Radio, List } from '@opentiny/vue'
<script>
import { Radio } from '@opentiny/vue'
export default {
components: {
TinyRadio: Radio,
TinyList: List
TinyRadio: Radio
},
data() {
return {
value1: '1',
value2: '1',
dataList: [
{
id: '1',
content: '主文本1',
subtext: '次文本1',
contentdes: '这是描述文本1'
},
{
id: '2',
content: '主文本2',
subtext: '次文本2',
contentdes: '这是描述文本2'
}
],
dataList1: [
{
id: '1',
content: '主文本1',
subtext: '',
contentdes: '这是描述文本1'
},
{
id: '2',
content: '主文本2',
subtext: '',
contentdes: '这是描述文本2'
}
]
}
},
methods: {
clickFn(list) {
if (list.id) {
this.value1 = list.id
}
value: false
}
}
}
@ -89,39 +22,8 @@ export default {
<style>
.demo {
background: #eeeeee;
height: 100%;
overflow-y: scroll;
}
.demo-title {
padding-right: 16px;
padding-left: 16px;
margin-top: 0.77em;
margin-bottom: 0.3em;
color: #666;
font-size: 14px;
}
.demo-list {
position: relative;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
padding: 8px 16px;
}
.withlist {
margin-top: 20px;
}
.demo .tiny-mobile-list__content-des {
margin-top: 4px;
color: #999;
font-size: 12px;
line-height: 1.6;
text-align: justify;
}
.demo .tiny-mobile-radio__label {
display: none;
padding: 20px;
}
</style>

View File

@ -1,27 +0,0 @@
<template>
<div class="radio-wrap">
<tiny-radio v-model="value" label="1" border>单选框 1</tiny-radio>
<tiny-radio v-model="value" label="2" border>单选框 2</tiny-radio>
</div>
</template>
<script lang="jsx">
import { Radio } from '@opentiny/vue'
export default {
components: {
TinyRadio: Radio
},
data() {
return {
value: '1'
}
}
}
</script>
<style scoped>
.radio-wrap {
padding: 20px;
}
</style>

View File

@ -1,11 +1,12 @@
<template>
<div class="radio-wrap">
<tiny-radio v-model="value" label="1" border disabled text="单选框 1"></tiny-radio>
<tiny-radio v-model="value" label="2" border name="name">单选框 2</tiny-radio>
<div class="demo">
<p>禁用</p>
<tiny-radio v-model="value" label="1" disabled>我同意</tiny-radio>
<tiny-radio v-model="value" label="2" disabled>我拒绝</tiny-radio>
</div>
</template>
<script lang="jsx">
<script>
import { Radio } from '@opentiny/vue'
export default {
@ -20,8 +21,10 @@ export default {
}
</script>
<style scoped>
.radio-wrap {
<style>
.demo {
height: 100%;
overflow-y: scroll;
padding: 20px;
}
</style>

View File

@ -1,32 +0,0 @@
<template>
<div class="radio-wrap">
<tiny-radio v-model="value" label="1" @change="handleChange">单选框 1</tiny-radio>
<tiny-radio v-model="value" label="2" @change="handleChange">单选框 2</tiny-radio>
</div>
</template>
<script lang="jsx">
import { Radio } from '@opentiny/vue'
export default {
components: {
TinyRadio: Radio
},
data() {
return {
value: '1'
}
},
methods: {
handleChange(val) {
console.log('当前单选框为: ' + val)
}
}
}
</script>
<style scoped>
.radio-wrap {
padding: 20px;
}
</style>

View File

@ -0,0 +1,37 @@
<template>
<div class="demo">
<p>默认</p>
<tiny-radio v-model="value" label="1" @change="changeAction"></tiny-radio>
<tiny-radio v-model="value" label="2" @change="changeAction"></tiny-radio>
<p>{{ text }}</p>
</div>
</template>
<script>
import { Radio } from '@opentiny/vue'
export default {
components: {
TinyRadio: Radio
},
data() {
return {
value: '1',
text: '男'
}
},
methods: {
changeAction(value) {
this.text = value === '1' ? '男' : '女'
}
}
}
</script>
<style>
.demo {
height: 100%;
overflow-y: scroll;
padding: 20px;
}
</style>

View File

@ -0,0 +1,30 @@
<template>
<div class="demo">
<p>默认</p>
<tiny-radio v-model="value" label="1"></tiny-radio>
<tiny-radio v-model="value" label="2"></tiny-radio>
</div>
</template>
<script>
import { Radio } from '@opentiny/vue'
export default {
components: {
TinyRadio: Radio
},
data() {
return {
value: '1'
}
}
}
</script>
<style>
.demo {
height: 100%;
overflow-y: scroll;
padding: 20px;
}
</style>

View File

@ -14,41 +14,41 @@ export default {
},
codeFiles: ['base.vue']
},
{
demoId: 'border',
name: {
'zh-CN': '显示边框',
'en-US': 'button type'
},
desc: {
'zh-CN': '<p>显示边框</p>',
'en-US': '<p>button type</p>'
},
codeFiles: ['border.vue']
},
{
demoId: 'disabled',
name: {
'zh-CN': '是否禁用',
'en-US': 'button round'
'zh-CN': '禁用状态',
'en-US': 'disabled'
},
desc: {
'zh-CN': '<p>是否禁用</p>',
'en-US': '<p>button round</p>'
'zh-CN': '<p>禁用</p>',
'en-US': '<p>disabled</p>'
},
codeFiles: ['disabled.vue']
},
{
demoId: 'event-change',
demoId: 'label',
name: {
'zh-CN': '值改变事件',
'en-US': 'events'
'zh-CN': '自定义label',
'en-US': 'custom label'
},
desc: {
'zh-CN': '<p>值改变事件</p>',
'en-US': '<p>bbutton click</p>'
'zh-CN': '<p>自定义label</p>',
'en-US': '<p>custom label</p>'
},
codeFiles: ['event-change.vue']
codeFiles: ['label.vue']
},
{
demoId: 'event',
name: {
'zh-CN': '选中状态事件',
'en-US': 'event'
},
desc: {
'zh-CN': '<p>事件</p>',
'en-US': '<p>event</p>'
},
codeFiles: ['event.vue']
}
],
apis: [
@ -58,7 +58,7 @@ export default {
properties: [
{
name: 'disabled',
type: 'Boolean',
type: 'boolean',
defaultValue: 'false',
desc: {
'zh-CN': '<p>是否禁用</p>',
@ -66,55 +66,45 @@ export default {
},
demoId: 'disabled'
},
{
name: 'border',
type: 'Boolean',
defaultValue: 'false',
desc: {
'zh-CN': '<p>是否显示边框</p>',
'en-US': 'display different button'
},
demoId: 'border'
},
{
name: 'label',
type: 'Object | String',
type: 'object | string',
defaultValue: '',
desc: {
'zh-CN': '<p>Radio 的 value,该属性默认为{}</p>',
'en-US': 'display different button'
},
demoId: 'event-change'
demoId: 'label'
},
{
name: 'name',
type: 'String',
type: 'string',
defaultValue: '',
desc: {
'zh-CN': '<p>原生 name 属性</p>',
'en-US': 'display different button'
},
demoId: 'disabled'
demoId: 'base'
},
{
name: 'text',
type: 'String',
type: 'string',
defaultValue: '',
desc: {
'zh-CN': '<p>文本</p>',
'en-US': 'display different button'
},
demoId: 'disabled'
demoId: 'base'
},
{
name: 'value',
type: 'Object | String',
type: 'object | string',
defaultValue: '{}',
desc: {
'zh-CN': '<p>绑定值,该属性默认为{}</p>',
'en-US': 'display different button'
},
demoId: 'border'
demoId: 'base'
}
],
events: [
@ -126,7 +116,7 @@ export default {
'zh-CN': '<p>绑定值变化时触发的事件,可获取changeValue</p>',
'en-US': 'Click'
},
demoId: 'event-change'
demoId: 'event'
}
],
slots: [

View File

@ -28,7 +28,7 @@
}
&,
&__inner,
&__outer,
&__input {
position: relative;
display: inline-block;
@ -43,78 +43,91 @@
vertical-align: middle;
}
&__inner {
border: 1px solid transparent;
&__outer {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 2px;
top: 2px;
background-color: #fff;
width: var(--ti-mobile-radio-size-outer, 20px);
height: var(--ti-mobile-radio-size-outer, 20px);
border: 1.5px solid var(--ti-mobile-radio-border-color-default);
border-radius: 50%;
width: var(--ti-mobile-radio-size, 24px);
height: var(--ti-mobile-radio-size, 24px);
background-color: transparent;
cursor: pointer;
box-sizing: border-box;
transition-duration: 0.2s;
transition-property: color, border-color, background-color;
&::after {
content: '';
width: 8px;
height: 12px;
border-width: 0.1em;
border-style: solid;
border-color: var(--ti-mobile-radio-checked-color, #f36f64);
border-left: 0;
border-top: 0;
position: absolute;
left: 50%;
top: 45%;
transform: translate(-50%, -50%) rotate(45deg) scale(0);
transform-origin: center;
transition: all 0.15s ease-in;
&:after {
border-color: var(--ti-mobile-radio-checked-color);
opacity: 0;
}
}
&:hover:not(.is-disabled) &__inner,
&.is-checked &__inner {
&::after {
transform: translate(-50%, -50%) rotate(45deg) scale(1);
&__inner {
width: var(--ti-mobile-radio-size-inner, 10px);
height: var(--ti-mobile-radio-size-inner, 10px);
background-color: transparent;
box-sizing: border-box;
border-radius: 999px;
&:after {
width: 10px;
height: 10px;
position: absolute;
left: 50%;
top: 45%;
transform-origin: center;
}
}
&:hover:not(.is-disabled) &__outer,
&.is-checked &__outer {
&:after {
opacity: 1;
}
}
&.is-disabled &__inner,
&.is-bordered:not(.is-disabled):hover &__inner {
border-color: var(--ti-mobile-radio-checked-color #1476ff);
}
&.is-checked &__inner {
border-color: var(--ti-mobile-radio-checked-color);
background-color: var(--ti-mobile-radio-checked-color);
}
&.is-checked &__outer {
border-color: var(--ti-mobile-radio-checked-color);
}
&.is-disabled &__outer,
&.is-disabled &__label {
cursor: not-allowed;
}
&.is-disabled.is-checked &__inner {
&.is-disabled.is-checked &__outer {
border-color: var(--ti-mobile-radio-color-disabled);
&:after {
border-color: var(--ti-mobile-radio-disabled-color, #ddd);
border-color: var(--ti-mobile-radio-color-disabled);
}
}
&.is-bordered &__inner {
border-color: var(--ti-mobile-radio-disabled-color, #ddd);
&.is-disabled.is-checked &__inner {
background-color: var(--ti-mobile-radio-color-disabled);
border-color: var(--ti-mobile-radio-color-disabled);
&::after {
border-color: var(--ti-mobile-radio-inner-border-color, #fff);
&:after {
border-color: var(--ti-mobile-radio-color-disabled);
}
}
&.is-bordered:not(.is-disabled):hover &__inner {
border-color: var(--ti-mobile-radio-checked-color, #f36f64);
}
&.is-disabled &__inner {
background-color: var(--ti-mobile-radio-bg-color-disabled);
border-color: var(--ti-mobile-radio-color-disabled);
&.is-bordered.is-checked &__inner {
border-color: var(--ti-mobile-radio-checked-color, #f36f64);
background-color: var(--ti-mobile-radio-checked-color, #f36f64);
}
&.is-bordered.is-disabled.is-checked &__inner {
background-color: var(--ti-mobile-radio-disabled-color, #ddd);
border-color: var(--ti-mobile-radio-disabled-color, #ddd);
&::after {
border-color: var(--ti-mobile-radio-inner-border-color, #fff);
&:after {
border-color: var(--ti-mobile-radio-color-disabled);
background-color: var(--ti-mobile-radio-bg-color-disabled);
}
}
@ -131,7 +144,8 @@
}
&__label {
font-size: var(--ti-mobile-radio-label-font-size, 16px);
font-size: var(--ti-mobile-radio-label-font-size);
color: var(--ti-mobile-radio-label-text-color);
padding-left: 8px;
vertical-align: middle;
}

View File

@ -1,7 +1,21 @@
:root {
// 组件尺寸
--ti-mobile-radio-size: 24px;
--ti-mobile-radio-checked-color: #f36f64;
--ti-mobile-radio-disabled-color: #ddd;
--ti-mobile-radio-inner-border-color: var(--ti-mobile-base-color-light, #fff);
--ti-mobile-radio-label-font-size: 16px;
// 外圈尺寸
--ti-mobile-radio-size-outer: 20px;
// 内圆尺寸
--ti-mobile-radio-size-inner: 10px;
--ti-mobile-radio-checked-color: var(--ti-mobile-color-icon-link, #1476ff);
// 外圈默认颜色
--ti-mobile-radio-border-color-default: var(--ti-mobile-color-border-default, #c2c2c2);
// 不可用状态填充颜色
--ti-mobile-radio-color-disabled: var(--ti-mobile-color-border-disabled, #dbdbdb);
// 不可用状态背景色
--ti-mobile-radio-bg-color-disabled: var(--ti-mobile-color-bg-container-2, #fafafa);
// 文字大小
--ti-mobile-radio-label-font-size: var(--ti-mobile-font-size-l, 16px);
// 文字颜色
--ti-mobile-radio-label-text-color: var(--ti-mobile-color-text-primary, #191919);
// 文字左边距
--ti-mobile-radio-label-padding-left: var(--ti-mobile-space-3x, 12px);
}

View File

@ -12,12 +12,7 @@
<template>
<label
class="tiny-mobile-radio"
:class="[
{ 'is-disabled': state.isDisabled },
{ 'is-focus': state.focus },
{ 'is-bordered': border },
{ 'is-checked': state.model === label }
]"
:class="[{ 'is-disabled': state.isDisabled }, { 'is-focus': state.focus }, { 'is-checked': state.model === label }]"
role="radio"
:aria-checked="state.model === label"
:aria-disabled="state.isDisabled"
@ -25,7 +20,10 @@
@keydown.space.stop.prevent="state.model = state.isDisabled ? state.model : label"
>
<div class="tiny-mobile-radio__input">
<span class="tiny-mobile-radio__inner"></span>
<div class="tiny-mobile-radio__outer">
<div class="tiny-mobile-radio__inner"></div>
</div>
<input
ref="radio"
class="tiny-mobile-radio__original"
@ -53,8 +51,8 @@ import { props, setup, defineComponent } from '@opentiny/vue-common'
import '@opentiny/vue-theme-mobile/radio/index.less'
export default defineComponent({
emits: ['change'],
props: [...props, 'modelValue', 'events', 'label', 'text', 'disabled', 'name', 'border', 'size'],
emits: ['change', 'update:modelValue'],
props: [...props, 'modelValue', 'events', 'label', 'text', 'disabled', 'name'],
inheritAttrs: false,
setup(props, context) {
return setup({ props, context, renderless, api })