init
This commit is contained in:
79
uni_modules/nutui-uni/components/codeinput/codeinput.ts
Normal file
79
uni_modules/nutui-uni/components/codeinput/codeinput.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { ExtractPropTypes } from 'vue'
|
||||
import { CHANGE_EVENT, INPUT_EVENT, UPDATE_MODEL_EVENT } from '../_constants'
|
||||
import { commonProps, isNumber, isString, makeNumericProp, makeStringProp, truthProp } from '../_utils'
|
||||
|
||||
export const codeinputProps = {
|
||||
...commonProps,
|
||||
/**
|
||||
* @description 键盘弹起时,是否自动上推页面
|
||||
*/
|
||||
adjustPosition: truthProp,
|
||||
/**
|
||||
* @description 最大输入长度
|
||||
*/
|
||||
maxlength: makeNumericProp(4),
|
||||
/**
|
||||
* @description 是否用圆点填充
|
||||
*/
|
||||
dot: Boolean,
|
||||
/**
|
||||
* @description 显示模式,可选值:`box`-盒子模式,`line`-底部横线模式
|
||||
*/
|
||||
mode: makeStringProp<'box' | 'line'>('box'),
|
||||
/**
|
||||
* @description 是否细边框
|
||||
*/
|
||||
hairline: Boolean,
|
||||
/**
|
||||
* @description 字符间的距离
|
||||
*/
|
||||
space: makeNumericProp(10),
|
||||
/**
|
||||
* @description 预置值
|
||||
*/
|
||||
modelValue: makeNumericProp(''),
|
||||
/**
|
||||
* @description 是否自动获取焦点
|
||||
*/
|
||||
focus: Boolean,
|
||||
/**
|
||||
* @description 字体是否加粗
|
||||
*/
|
||||
bold: Boolean,
|
||||
/**
|
||||
* @description 字体颜色
|
||||
*/
|
||||
customColor: makeStringProp('#606266'),
|
||||
/**
|
||||
* @description 字体大小
|
||||
*/
|
||||
fontSize: makeNumericProp(18),
|
||||
/**
|
||||
* @description 输入框的大小,宽等于高
|
||||
*/
|
||||
size: makeNumericProp(35),
|
||||
/**
|
||||
* @description 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true
|
||||
*/
|
||||
disabledKeyboard: Boolean,
|
||||
/**
|
||||
* @description 边框和线条颜色
|
||||
*/
|
||||
borderColor: makeStringProp('#c9cacc'),
|
||||
/**
|
||||
* @description 是否禁止输入"."符号
|
||||
*/
|
||||
disabledDot: truthProp,
|
||||
}
|
||||
|
||||
export type CodeInputProps = ExtractPropTypes<typeof codeinputProps>
|
||||
|
||||
export const codeinputEmits = {
|
||||
[CHANGE_EVENT]: (val: string) => isString(val),
|
||||
[INPUT_EVENT]: (val: string) => isString(val),
|
||||
finish: (val: string) => isString(val),
|
||||
[UPDATE_MODEL_EVENT]: (val: number | string) => isString(val) || isNumber(val),
|
||||
|
||||
}
|
||||
|
||||
export type CodeInputEmits = typeof codeinputEmits
|
||||
159
uni_modules/nutui-uni/components/codeinput/codeinput.vue
Normal file
159
uni_modules/nutui-uni/components/codeinput/codeinput.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<script setup lang="ts">
|
||||
import type { CSSProperties } from 'vue'
|
||||
import { computed, defineComponent, nextTick, ref, watch } from 'vue'
|
||||
import { CHANGE_EVENT, INPUT_EVENT, PREFIX, UPDATE_MODEL_EVENT } from '../_constants'
|
||||
import { getMainClass, getPx } from '../_utils'
|
||||
import { codeinputEmits, codeinputProps } from './codeinput'
|
||||
|
||||
const props = defineProps(codeinputProps)
|
||||
|
||||
const emit = defineEmits(codeinputEmits)
|
||||
const classes = computed(() => {
|
||||
return getMainClass(props, componentName)
|
||||
})
|
||||
const inputValue = ref('')
|
||||
const isFocus = ref(props.focus)
|
||||
|
||||
const codeLength = computed(() => {
|
||||
return Array.from({ length: Number(props.maxlength) })
|
||||
})
|
||||
const itemStyle = computed(() => {
|
||||
return (index: number) => {
|
||||
const style: CSSProperties = {
|
||||
width: `${props.size}px`,
|
||||
height: `${props.size}px`,
|
||||
}
|
||||
// 盒子模式下,需要额外进行处理
|
||||
if (props.mode === 'box') {
|
||||
// 设置盒子的边框,如果是细边框,则设置为0.5px宽度
|
||||
style.border = `${props.hairline ? 0.5 : 1}px solid ${props.borderColor}`
|
||||
// 如果盒子间距为0的话
|
||||
if (getPx(props.space) === 0) {
|
||||
// 给第一和最后一个盒子设置圆角
|
||||
if (index === 0) {
|
||||
style.borderTopLeftRadius = '3px'
|
||||
style.borderBottomLeftRadius = '3px'
|
||||
}
|
||||
if (index === codeLength.value.length - 1) {
|
||||
style.borderTopRightRadius = '3px'
|
||||
style.borderBottomRightRadius = '3px'
|
||||
}
|
||||
// 最后一个盒子的右边框需要保留
|
||||
if (index !== codeLength.value.length - 1)
|
||||
style.borderRight = 'none'
|
||||
}
|
||||
}
|
||||
if (index !== codeLength.value.length - 1) {
|
||||
// 设置验证码字符之间的距离,通过margin-right设置,最后一个字符,无需右边框
|
||||
style.marginRight = `${props.space}px`
|
||||
}
|
||||
else {
|
||||
// 最后一个盒子的有边框需要保留
|
||||
style.marginRight = 0
|
||||
}
|
||||
|
||||
return style
|
||||
}
|
||||
})
|
||||
const codeArray = computed(() => {
|
||||
return String(inputValue.value).split('')
|
||||
})
|
||||
const lineStyle = computed(() => {
|
||||
const style: CSSProperties = {}
|
||||
style.height = props.hairline ? '2px' : '4px'
|
||||
style.width = `${props.size}px`
|
||||
// 线条模式下,背景色即为边框颜色
|
||||
style.backgroundColor = props.borderColor
|
||||
return style
|
||||
})
|
||||
|
||||
watch(() => props.modelValue, (val) => {
|
||||
// 转为字符串,超出部分截掉
|
||||
inputValue.value = String(val).substring(0, +props.maxlength)
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
function inputHandler(e: { detail: { value: string } }) {
|
||||
const value = e.detail.value
|
||||
emit(UPDATE_MODEL_EVENT, value)
|
||||
|
||||
inputValue.value = value
|
||||
// 是否允许输入“.”符号
|
||||
if (props.disabledDot) {
|
||||
nextTick(() => {
|
||||
inputValue.value = value.replace('.', '')
|
||||
})
|
||||
}
|
||||
// 未达到maxlength之前,发送change事件,达到后发送finish事件
|
||||
emit(CHANGE_EVENT, value)
|
||||
// 修改通过v-model双向绑定的值
|
||||
emit(INPUT_EVENT, value)
|
||||
// 达到用户指定输入长度时,发出完成事件
|
||||
if (String(value).length >= Number(props.maxlength))
|
||||
emit('finish', value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
const componentName = `${PREFIX}-code-input`
|
||||
|
||||
export default defineComponent({
|
||||
name: componentName,
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view :class="classes" :style="customStyle">
|
||||
<view
|
||||
v-for="(item, index) in codeLength"
|
||||
:key="index"
|
||||
class="nut-code-input__item"
|
||||
:style="[itemStyle(index)]"
|
||||
>
|
||||
<view v-if="dot && codeArray.length > index" class="nut-code-input__item__dot" />
|
||||
<text
|
||||
v-else
|
||||
:style="{
|
||||
fontSize: `${props.fontSize}px`,
|
||||
fontWeight: bold ? 'bold' : 'normal',
|
||||
color: customColor,
|
||||
}"
|
||||
>
|
||||
{{ codeArray[index] }}
|
||||
</text>
|
||||
<view v-if="mode === 'line'" class="nut-code-input__item__line" :style="[lineStyle]" />
|
||||
<!-- #ifndef APP-PLUS -->
|
||||
<view
|
||||
v-if="isFocus && codeArray.length === index"
|
||||
:style="{ backgroundColor: customColor }"
|
||||
class="nut-code-input__item__cursor"
|
||||
/>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<input
|
||||
:disabled="disabledKeyboard"
|
||||
type="number"
|
||||
:focus="focus"
|
||||
:value="inputValue"
|
||||
:maxlength="+maxlength"
|
||||
:adjustPosition="adjustPosition"
|
||||
class="nut-code-input__input"
|
||||
:style="{
|
||||
height: `${props.size}px`,
|
||||
}"
|
||||
@input="inputHandler"
|
||||
@focus="isFocus = true"
|
||||
@blur="isFocus = false"
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import './index';
|
||||
</style>
|
||||
76
uni_modules/nutui-uni/components/codeinput/index.scss
Normal file
76
uni_modules/nutui-uni/components/codeinput/index.scss
Normal file
@@ -0,0 +1,76 @@
|
||||
.nut-code-input {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
&__item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&__text {
|
||||
font-size: 15px;
|
||||
color: $code-input-content-color;
|
||||
}
|
||||
|
||||
&__dot {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
background-color: $title-color2;
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
&__line {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 40px;
|
||||
height: 4px;
|
||||
background-color: $code-input-content-color;
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
/* #ifndef APP-PLUS */
|
||||
&__cursor {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: $code-input-cursor-width;
|
||||
height: $code-input-cursor-height;
|
||||
transform: translate(-50%, -50%);
|
||||
animation: $code-input-cursor-animation-duration nut-cursor-flicker infinite;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
}
|
||||
|
||||
&__input {
|
||||
// 之所以需要input输入框,是因为有它才能唤起键盘
|
||||
// 这里将它设置为两倍的屏幕宽度,再将左边的一半移出屏幕,为了不让用户看到输入的内容
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -325px;
|
||||
width: 700px;
|
||||
text-align: left;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/* #ifndef APP-PLUS */
|
||||
// stylelint-disable-next-line keyframes-name-pattern
|
||||
@keyframes nut-cursor-flicker {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
1
uni_modules/nutui-uni/components/codeinput/index.ts
Normal file
1
uni_modules/nutui-uni/components/codeinput/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type * from './codeinput'
|
||||
Reference in New Issue
Block a user