未验证 提交 8a1b08db 编写于 作者: L love_forever 提交者: GitHub

Merge pull request #404 from guoxiao158/review-gx

fix: input组件拆分
......@@ -482,6 +482,16 @@
"sort": 6,
"show": true,
"author": "Drjingfubo"
},
{
"version": "3.0.0",
"name": "TextArea",
"type": "component",
"cName": "文本域",
"desc": "文本输入",
"sort": 7,
"show": true,
"author": "gx"
}
]
},
......
......@@ -57,34 +57,6 @@
placeholder="支持小数点的输入"
label="数字:"
/>
<h2>文本域</h2>
<nut-input
v-model:value="state.val7"
@change="change"
:autosize="true"
type="textarea"
placeholder="文本域"
label="留言:"
/>
<nut-input
v-model:value="state.val7"
@change="change"
rows="5"
type="textarea"
placeholder="设置输入五行"
label="留言:"
/>
<h2>显示字数统计</h2>
<nut-input
v-model:value="state.val8"
@change="change"
rows="5"
:limitShow="true"
maxLength="20"
type="textarea"
placeholder="设置输入五行"
label="留言:"
/>
</div>
</template>
......@@ -120,6 +92,7 @@ export default createDemo({
const clear = (num: string | number) => {
console.log('clear:', num);
};
return {
state,
change,
......
......@@ -20,8 +20,20 @@ app.use(input);
双向绑定
```html
<nut-input v-model:value="state.val1" @change="change" label="标题:" />
<nut-input
v-model:value="state.val1"
@change="change"
@focus="focus"
@blur="blur"
label="文本"
/>
<nut-input placeholder="请输入文本"
@change="change"
v-model:value="state.val0"
:requireShow="true"
label="文本"
@clear="clear"
/>
```
### 禁用和只读
......@@ -44,19 +56,7 @@ app.use(input);
<nut-input v-model:value="state.val5" @change="change" type="digit" label="整数:" />
<nut-input v-model:value="state.val6" @change="change" type="digit" placeholder="支持小数点的输入" label="数字:"/>
```
### 文本域
```html
<nut-input v-model:value="state.val7" @change="change" autosize="true" type="textarea" placeholder="文本域" label="留言:"/>
<nut-input v-model:value="state.val7" @change="change" rows="5" type="textarea" placeholder="设置输入五行" label="留言:"/>
```
### 文本域字数统计
```html
<nut-input v-model:value="state.val8" @change="change" rows="5" limitShow="true" maxLength="20" type="textarea" placeholder="设置输入五行" label="留言:"/>
```
| 参数 | 说明 | 类型 | 默认值 |
......@@ -64,15 +64,13 @@ app.use(input);
| type | 类型,可选值为 `text` `textarea` `number` 等 | String |`text` |
| value | 输入值,双向绑定 | String | - |
| placeholder | 为空时占位符 | String | - |
| placeholder-style | placeholder 样式 | String | - |
| label | 左侧文案 | string | - |
| requireShow |左侧*号是否展示 | boolean | `false` |
| disabled | 是否禁用 | boolean | `false` |
| readonly | 是否只读 | boolean | `false` |
| clear-btn | 是否带清除按钮(icon) | boolean | `true` |
| required | 是否带必填的*号,且blur事件做非空校验 | boolean | `false` |
| maxlength | 限制最长输入字符 | string/number | - |
| rows | textarea时高度 | string/number | 2 |
| limit-show | textarea时是否展示输入字符。须设置maxlength | boolean | `false` |
| disableClear | 禁止展示清除icon | boolean | false |
| textAlign | 文本位置 | string | `left` |
| change | 输入内容时触发 | function | - |
| focus | 聚焦时触发 | function | - |
| blur | 失焦时触发 | function | - |
......
......@@ -28,29 +28,6 @@
position: absolute;
right: 15px;
}
.nut-text {
flex: 1;
padding: 0 10px;
.nut-text-limit {
float: right;
color: rgba(153, 153, 153, 1);
}
.nut-text-core {
outline: none;
display: block;
box-sizing: border-box;
width: 100%;
min-width: 0;
margin: 0;
padding: 0;
color: #323233;
line-height: inherit;
text-align: left;
background-color: transparent;
border: 0;
resize: none;
}
}
}
.nut-input-disabled {
color: #c8c9cc !important;
......
<template>
<view :class="['nut-input', { 'nut-input-disabled': disabled }]">
<view :class="classes">
<view class="nut-input-label">
<view class="nut-input-require" v-if="requireShow">*</view>
<view v-if="label" class="label-string">{{ label }}</view>
</view>
<view v-if="type === 'textarea'" class="nut-text">
<textarea
:style="styles"
:rows="rows"
@input="valueChange"
v-model="state.curretvalue"
class="nut-text-core"
:maxlength="maxLength"
:placeholder="placeholder"
:disabled="disabled"
:readonly="readonly"
>
</textarea>
<span class="nut-text-limit" v-if="limitShow">
<span :class="[{ 'nut-field-over': state.textNum > maxLength }]">{{
state.textNum
}}</span>
<span>/{{ maxLength }}</span>
</span>
</view>
<input
v-else
class="input-text"
:style="styles"
:type="type"
......@@ -43,7 +21,7 @@
@click="handleClear"
class="nut-textinput-clear"
v-if="!disableClear && !readonly"
v-show="type !== 'textarea' && active"
v-show="active && state.curretvalue.length > 0"
>
<nut-icon name="close-little" size="12px"></nut-icon>
</view>
......@@ -54,43 +32,30 @@ import { ref, toRefs, reactive, computed } from 'vue';
import { createComponent } from '@/utils/create';
import { formatNumber } from './util';
const { create } = createComponent('input');
const { componentName, create } = createComponent('input');
interface Events {
eventName: 'change' | 'focus' | 'blur' | 'clear' | 'update:value';
params: (string | number | Event)[];
}
export default create({
props: {
type: {
type: String,
default: 'text'
},
textAlign: {
type: String,
default: 'left'
},
limitShow: {
type: Boolean,
default: false
},
maxLength: {
type: String,
value: {
type: [String, Number],
default: ''
},
requireShow: {
type: Boolean,
default: false
},
rows: {
placeholder: {
type: String,
default: ''
default: '请输入信息'
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请输入信息'
},
readonly: {
requireShow: {
type: Boolean,
default: false
},
......@@ -98,12 +63,16 @@ export default create({
type: Boolean,
default: false
},
autosize: {
readonly: {
type: Boolean,
default: false
},
value: {
type: [String, Number],
textAlign: {
type: String,
default: 'left'
},
maxLength: {
type: String,
default: ''
},
disableClear: {
......@@ -115,25 +84,13 @@ export default create({
emits: ['change', 'update:value', 'blur', 'focus', 'clear', 'error'],
setup(props, { emit }) {
interface Events {
eventName:
| 'change'
| 'focus'
| 'blur'
| 'clear'
| 'update:value'
| 'error';
params: (string | number | Event)[];
}
const {
label,
placeholder,
disabled,
readonly,
requireShow,
maxLength,
rows
maxLength
} = props;
const { value } = toRefs(props);
const active = ref(false);
......@@ -141,14 +98,15 @@ export default create({
curretvalue: value,
textNum: String(value.value).length
});
const classes = computed(() => {
return {
[componentName]: true,
'nut-input-disabled': disabled
};
});
const styles = computed(() => {
const rize =
props.type == 'textarea'
? `'resize':${props.autosize ? 'none' : 'horizontal'}`
: '';
return {
'text-align': props.textAlign,
rize
'text-align': props.textAlign
};
});
const emitChange = (envs: Array<Events>) => {
......@@ -162,12 +120,6 @@ export default create({
if (maxLength && val.length > Number(maxLength)) {
val = val.slice(0, Number(maxLength));
emitChange([
{
eventName: 'error',
params: [val]
}
]);
}
if (props.type == 'digit') {
val = formatNumber(val, true);
......@@ -176,8 +128,6 @@ export default create({
val = formatNumber(val, false);
}
state.textNum = val.length;
// input.value = val;
//state.curretvalue = val;
emitChange([
{
eventName: 'update:value',
......@@ -243,7 +193,6 @@ export default create({
placeholder,
label,
disabled,
rows,
state,
styles,
active,
......@@ -252,6 +201,7 @@ export default create({
valueFocus,
valueBlur,
handleClear,
classes,
emitChange
};
}
......
<template>
<div class="demo-nopading">
<h2>基础用法</h2>
<nut-textarea
v-model:value="state.val0"
@change="change"
rows="5"
placeholder="高度可拉伸"
:autosize="true"
label="留言:"
/>
<h2>显示字数统计</h2>
<nut-textarea
v-model:value="state.val1"
@change="change"
rows="5"
:limitShow="true"
maxLength="20"
type="textarea"
placeholder="设置输入五行"
label="留言:"
/>
</div>
</template>
<script lang="ts">
import { reactive } from 'vue';
import { createComponent } from '@/utils/create';
const { createDemo } = createComponent('textarea');
export default createDemo({
setup() {
const state = reactive({
val0: '',
val1: '初始数据'
});
setTimeout(function() {
state.val1 = '异步测试数据,2秒';
}, 2000);
const change = (num: string | number) => {
console.log('change: ', num);
};
const focus = (num: string | number) => {
console.log('focus:', num);
};
const blur = (num: string | number) => {
console.log('blur:', num);
};
const clear = (num: string | number) => {
console.log('clear:', num);
};
return {
state,
change,
blur,
clear,
focus
};
}
});
</script>
<style lang="scss" scoped>
.demo-nopading {
height: 100%;
background: #f7f8fa;
overflow-x: hidden;
overflow-y: auto;
padding: 0;
padding-top: 57px;
h2 {
padding-left: 25px;
margin-top: 25px;
margin-bottom: 10px;
color: #909ca4;
}
}
</style>
# Input 输入框组件
### 介绍
### 安装
``` javascript
import { createApp } from 'vue';
import { input } from '@nutui/nutui';
const app = createApp();
app.use(input);
```
## 代码演示
### 基础用法
```html
<nut-textarea
v-model:value="state.val0"
@change="change"
rows="5"
placeholder="高度可拉伸"
:autosize="true"
label="留言:"
/>
```
### 显示字数统计
```html
<nut-textarea
v-model:value="state.val1"
@change="change"
rows="5"
:limitShow="true"
maxLength="20"
type="textarea"
placeholder="设置输入五行"
label="留言:"
/>
```
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------------------------|--------|------------------|
| value | 输入值,双向绑定 | String | - |
| placeholder | 为空时占位符 | String | - |
| label | 左侧文案 | string | - |
| maxlength | 限制最长输入字符 | string/number | - |
| rows | textarea时高度 | string/number | 2 |
| limit-show | textarea时是否展示输入字符。须设置maxlength | boolean | `false` |
| change | 输入内容时触发 | function | - |
| focus | 聚焦时触发 | function | - |
| blur | 失焦时触发 | function | - |
| clear | 点击清空时触发 | function | - |
.nut-textarea {
position: relative;
width: 100%;
padding: 10px 0px 10px 25px;
display: flex;
background: rgba(255, 255, 255, 1);
border-bottom: 1px solid rgba(234, 240, 251, 1);
font-size: 14px;
input {
width: 230px;
flex: 1;
padding: 0 10px;
}
.nut-input-label {
width: 80px;
overflow: hidden;
display: inline-block;
text-align: left;
.label-string {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.nut-textinput-clear {
width: 16px;
height: 16px;
position: absolute;
right: 15px;
}
.nut-text {
flex: 1;
padding: 0 10px;
.nut-text-limit {
float: right;
color: rgba(153, 153, 153, 1);
}
.nut-text-core {
outline: none;
display: block;
box-sizing: border-box;
width: 100%;
min-width: 0;
margin: 0;
padding: 0;
color: #323233;
line-height: inherit;
text-align: left;
background-color: transparent;
border: 0;
resize: none;
}
}
}
<template>
<view class="nut-textarea">
<view class="nut-input-label">
<view v-if="props.label" class="label-string">{{ props.label }}</view>
</view>
<view class="nut-text">
<textarea
:style="styles"
:rows="props.rows"
@input="valueChange"
v-model="state.curretvalue"
class="nut-text-core"
:maxlength="maxLength"
:placeholder="props.placeholder"
:disabled="props.disabled"
:readonly="props.readonly"
>
</textarea>
<view class="nut-text-limit" v-if="limitShow">
<view :class="[{ 'nut-field-over': state.textNum > maxLength }]">{{
state.textNum
}}</view>
<view>/{{ maxLength }}</view>
</view>
</view>
</view>
</template>
<script lang="ts">
import { ref, toRefs, reactive, computed } from 'vue';
import { createComponent } from '@/utils/create';
const { componentName, create } = createComponent('textarea');
interface Events {
eventName: 'change' | 'focus' | 'blur' | 'clear' | 'update:value';
params: (string | number | Event)[];
}
export default create({
props: {
textAlign: {
type: String,
default: 'left'
},
limitShow: {
type: Boolean,
default: false
},
maxLength: {
type: String,
default: ''
},
rows: {
type: String,
default: ''
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请输入信息'
},
readonly: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
autosize: {
type: Boolean,
default: false
},
value: {
type: [String, Number],
default: ''
}
},
emits: ['change', 'update:value', 'blur', 'focus', 'clear', 'error'],
setup(props, { emit }) {
const { maxLength } = props;
const { value } = toRefs(props);
const active = ref(false);
const state = reactive({
curretvalue: value,
textNum: String(value.value).length
});
const classes = computed(() => {
return {
[componentName]: true
};
});
const styles = computed(() => {
return {
'text-align': props.textAlign,
resize: props.autosize ? 'vertical' : 'none'
};
});
const emitChange = (envs: Array<Events>) => {
envs.forEach((item: Events) => {
return emit(item.eventName, ...item.params);
});
};
const valueChange = (e: Event) => {
const input = e.target as HTMLInputElement;
let val = input.value;
if (maxLength && val.length > Number(maxLength)) {
val = val.slice(0, Number(maxLength));
}
state.textNum = val.length;
emitChange([
{
eventName: 'update:value',
params: [val]
},
{
eventName: 'change',
params: [val]
}
]);
};
const valueFocus = (e: Event) => {
active.value = true;
const input = e.target as HTMLInputElement;
let val = input.value;
val = String(val);
emitChange([
{
eventName: 'update:value',
params: [state.curretvalue]
},
{
eventName: 'focus',
params: [val]
}
]);
};
const valueBlur = (e: Event) => {
setTimeout(() => {
active.value = false;
}, 400);
const input = e.target as HTMLInputElement;
let val = input.value;
val = String(val);
emitChange([
{
eventName: 'update:value',
params: [val]
},
{
eventName: 'blur',
params: [val]
}
]);
};
const handleClear = () => {
const val = '';
emitChange([
{
eventName: 'update:value',
params: [val]
},
{
eventName: 'clear',
params: [val]
}
]);
};
return {
props,
value,
state,
styles,
active,
maxLength,
valueChange,
valueFocus,
valueBlur,
handleClear,
emitChange
};
}
});
</script>
<style lang="scss">
@import 'index.scss';
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册