有了开发button的经验,copy过来删删改改获得最基础的框架:
<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { useProp, useNeumorphism } from '../mixin/neumorphism'
const props = defineProps({
...useProp,
...{
disabled: {
type: Boolean,
default: false
}
}
})
const { baseStyleObject } = useNeumorphism(props)
let styleObject = computed(() => ({
}))
</script>
<template>
<input
class="san-input"
:style="{...baseStyleObject,...styleObject}"
v-bind="$attrs"
@input="$emit('input', $event.target.value)"
@focus="$emit('focus', $event.target.value)"
@blur="$emit('blur', $event.target.value)"
@change="$emit('change', $event.target.value)"
/>
</template>
<script>
export default {
name: 'sanorin-input',
}
</script>
<style scoped>
@import "../../style/index.css";
.san-input{
width: 180px;
}
.san-input {
outline: none;
color: var(--text-color);
padding: 10px;
border: none;
border-radius: 5px;
background: linear-gradient(var(--linear-angle), var(--linear-left-color), var(--linear-right-color));
box-shadow: inset var(--shadow-ah) var(--shadow-av) var(--shadow-blur) var(--left-color), inset var(--shadow-bh) var(--shadow-bv) var(--shadow-blur) var(--right-color);
}
</style>
往下写,先支持disabled,支持disable的时候出现一个问题,我先在测试页面写下测试示例<sanorin-input v-model="input" :disabled="true"></sanorin-input>
这里已经成功禁用了输入,我想禁用输入的时候改变鼠标样式,就需要prop接收下来disabled
然后绑定到样式上:class="[{'is-disabled': disabled}]"
,于是,attrsv-bind="$attrs"
就接收不到diasable了,因此这里需要手动绑定下:disabled="disabled"
<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { useProp, useNeumorphism } from '../mixin/neumorphism'
const props = defineProps({
...useProp,
...{
disabled: {
type: Boolean,
default: false
}
}
})
const { baseStyleObject } = useNeumorphism(props)
let styleObject = computed(() => ({
}))
</script>
<template>
<input
class="san-input"
:class="[{'is-disabled': disabled}]"
:style="{...baseStyleObject,...styleObject}"
v-bind="$attrs"
@input="$emit('input', $event.target.value)"
@focus="$emit('focus', $event.target.value)"
@blur="$emit('blur', $event.target.value)"
@change="$emit('change', $event.target.value)"
:disabled="disabled"
/>
</template>
<script>
export default {
name: 'sanorin-input',
}
</script>
<style scoped>
@import "../../style/index.css";
.san-input{
width: 180px;
}
.san-input {
outline: none;
color: var(--text-color);
padding: 10px;
border: none;
border-radius: 5px;
background: linear-gradient(var(--linear-angle), var(--linear-left-color), var(--linear-right-color));
box-shadow: inset var(--shadow-ah) var(--shadow-av) var(--shadow-blur) var(--left-color), inset var(--shadow-bh) var(--shadow-bv) var(--shadow-blur) var(--right-color);
}
</style>
接下来加入is-clearable的代码
<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { useProp, useNeumorphism } from '../mixin/neumorphism'
const emit = defineEmits(['focus','blur','clear','input','change','update:modelValue'])
const handleFocus = (evt) => { focused.value = true; emit('focus', evt) }
const handleBlur = (evt) => { focused.value = false; emit('blur', evt) }
const handleClear = () => { emit('input', ''); emit('change', ''); emit('clear') }
const props = defineProps({
...useProp,
...{
modelValue: {
type: [String, Number],
default: ''
},
disabled: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
}
}
})
let hovering = ref(false)
let focused = ref(false)
let nativeInputValue = computed(() => props.value === null || props.value === undefined ? '' : String(props.value))
let showClear = computed(() => props.clearable && !props.disabled && (focused.value || hovering.value) && !!nativeInputValue)
const { baseStyleObject } = useNeumorphism(props)
let styleObject = computed(() => ({
}))
</script>
<template>
<div
class="san-input neumorphism flex"
:class="[{
'is-disabled': disabled,
}]"
:style="{...baseStyleObject,...styleObject}"
@mouseenter="hovering = true"
@mouseleave="hovering = false">
<input
:value="modelValue"
v-bind="$attrs"
:disabled="disabled"
@input="emit('update:modelValue', $event.target.value)"
@focus="handleFocus"
@blur="handleBlur"
@change="emit('change', $event.target.value)"
/>
<!-- 后置内容 -->
<span
v-if="showClear">
<span>
<i v-if="showClear"
class="iconfont san-qingchu"
@mousedown.prevent
@click="handleClear"
></i>
</span>
</span>
</div>
</template>
<script>
export default {
name: 'sanorin-input',
}
</script>
<style scoped>
@import "../../style/index.css";
@import "../../style/neumorphism.css";
.san-input{
height: 22px;
width: 250px;
padding: 10px;
border-radius: 5px;
}
.san-input > input{
flex: 1;
width: 220px;
background: transparent;
border: none;
outline: none;
}
</style>
接下来加入密码框,要有查看密码的功能,认情况input的type是passport,点击查看按钮,type就变成text。
<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { useProp, useNeumorphism } from '../mixin/neumorphism'
const emit = defineEmits(['focus','blur','clear','change','update:modelValue'])
const handleFocus = (evt) => { focused.value = true; emit('focus', evt) }
const handleBlur = (evt) => { focused.value = false; emit('blur', evt) }
const props = defineProps({
...useProp,
...{
modelValue: {
type: [String, Number],
default: ''
},
disabled: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
showPassword: {
type: Boolean,
default: false
},
}
})
let hovering = ref(false)
let focused = ref(false)
let nativeInputValue = computed(() => props.value === null || props.value === undefined ? '' : String(props.value))
// clearable
let showClear = computed(() => props.clearable && !props.disabled && (focused.value || hovering.value) && !!nativeInputValue)
const handleClear = () => { emit('update:modelValue', ''); emit('change', ''); emit('clear') }
// password
let passwordVisible = ref(false)
const handlePassword = () => { passwordVisible.value = !passwordVisible.value }
const { baseStyleObject } = useNeumorphism(props)
let styleObject = computed(() => ({
}))
</script>
<template>
<div
class="san-input neumorphism flex"
:class="[{
'is-disabled': disabled,
}]"
:style="{...baseStyleObject,...styleObject}"
@mouseenter="hovering = true"
@mouseleave="hovering = false">
<input
:value="modelValue"
v-bind="$attrs"
:disabled="disabled"
:type="showPassword ? (passwordVisible ? 'text': 'password') : type"
@input="emit('update:modelValue', $event.target.value)"
@focus="handleFocus"
@blur="handleBlur"
@change="emit('change', $event.target.value)"
/>
<!-- 后置内容 -->
<span v-if="showClear">
<i v-if="showClear"
class="iconfont san-qingchu"
@mousedown.prevent
@click="handleClear"
></i>
</span>
<span v-if="showPassword">
<i v-if="!passwordVisible"
class="iconfont san-bukejian"
@mousedown.prevent
@click="handlePassword"
></i>
<i v-if="passwordVisible"
class="iconfont san-kejian"
@mousedown.prevent
@click="handlePassword"
></i>
</span>
</div>
</template>
<script>
export default {
name: 'sanorin-input',
}
</script>
<style scoped>
@import "../../style/index.css";
@import "../../style/neumorphism.css";
.san-input{
height: 22px;
width: 250px;
padding: 10px;
border-radius: 5px;
}
.san-input > input{
flex: 1;
width: 220px;
background: transparent;
border: none;
outline: none;
}
</style>
接下来加入三点
icon
尺寸
textarea(初步)
<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { useProp, useNeumorphism } from '../mixin/neumorphism'
const input = ref() // 与html中ref=""对应,定位dom元素
const emit = defineEmits(['focus','blur','clear','change','update:modelValue'])
const handleFocus = (evt) => { focused.value = true; emit('focus', evt) }
const handleBlur = (evt) => { focused.value = false; emit('blur', evt) }
const props = defineProps({
...useProp,
...{
modelValue: {
type: [String, Number],
default: ''
},
disabled: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
showPassword: {
type: Boolean,
default: false
},
preIcon: {
type: String,
default: null,
},
postIcon: {
type: String,
default: null,
},
type: {
type: String,
default: 'text'
},
size: {
type: Number,
default: 40
},
}
})
let hovering = ref(false)
let focused = ref(false)
let nativeInputValue = computed(() => props.value === null || props.value === undefined ? '' : String(props.value))
// clearable
let showClear = computed(() => props.clearable && !props.disabled && (focused.value || hovering.value) && !!nativeInputValue)
const handleClear = () => { emit('update:modelValue', ''); emit('change', ''); emit('clear') }
// password
let passwordVisible = ref(false)
const handlePassword = () => { passwordVisible.value = !passwordVisible.value; focus() }
const focus = () => { input.value.focus(); setTimeout(() => { input.value.setSelectionRange(-1,-1) }) } // 点击密码后自动对焦并焦点至为最后一位
const { baseStyleObject } = useNeumorphism(props)
let styleObject = computed(() => ({
'--font-size': `${props.size-26}px`, '--line-height': `${props.size-20}px`,
}))
</script>
<template>
<div
class="san-input neumorphism flex"
:class="[{
'is-disabled': disabled,
}]"
:style="{...baseStyleObject,...styleObject}"
@mouseenter="hovering = true"
@mouseleave="hovering = false">
<!-- 前置内容 -->
<i v-if="preIcon" :class="[preIcon, 'iconfont']"></i>
<!-- 主体内容 -->
<input
v-if="type !== 'textarea'"
ref="input"
:value="modelValue"
v-bind="$attrs"
:disabled="disabled"
:type="showPassword ? (passwordVisible ? 'text': 'password') : type"
@input="emit('update:modelValue', $event.target.value)"
@focus="handleFocus"
@blur="handleBlur"
@change="emit('change', $event.target.value)"
/>
<textarea
v-else
ref="textarea"
:value="modelValue"
v-bind="$attrs"
:disabled="disabled"
@input="emit('update:modelValue', $event.target.value)"
@focus="handleFocus"
@blur="handleBlur"
@change="emit('change', $event.target.value)"
/>
<!-- 后置内容 -->
<i v-if="showClear" class="iconfont san-qingchu" @click="handleClear"></i>
<template v-if="showPassword">
<i v-if="!passwordVisible" class="iconfont san-bukejian" @click="handlePassword"></i>
<i v-if="passwordVisible" class="iconfont san-kejian" @click="handlePassword"></i>
</template>
<i v-if="postIcon" :class="[postIcon, 'iconfont']"></i>
</div>
</template>
<script>
export default {
name: 'sanorin-input',
}
</script>
<style scoped>
@import "../../style/index.css";
@import "../../style/neumorphism.css";
.san-input{
width: 250px;
padding: 10px;
border-radius: 5px;
}
.san-input > input{
flex: 1;
width: 220px;
background: transparent;
border: none;
outline: none;
padding: 0px;
font-size: var(--font-size);
line-height: var(--line-height);
}
.san-input > textarea{
flex: 1;
background: transparent;
border: none;
outline: none;
}
</style>
接下里增加输入长度限制
<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { useProp, useNeumorphism } from '../mixin/neumorphism'
const input = ref() // 与html中ref=""对应,定位dom元素
const emit = defineEmits(['focus','blur','clear','change','update:modelValue'])
const handleFocus = (evt) => { focused.value = true; emit('focus', evt) }
const handleBlur = (evt) => { focused.value = false; emit('blur', evt) }
const props = defineProps({
...useProp,
...{
modelValue: {
type: [String, Number],
default: ''
},
disabled: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
showPassword: {
type: Boolean,
default: false
},
preIcon: {
type: String,
default: null,
},
postIcon: {
type: String,
default: null,
},
type: {
type: String,
default: 'text'
},
size: {
type: Number,
default: 40
}
}
})
let hovering = ref(false)
let focused = ref(false)
let nativeInputValue = computed(() => props.value === null || props.value === undefined ? '' : String(props.value))
// clearable
let showClear = computed(() => props.clearable && !props.disabled && (focused.value || hovering.value) && !!nativeInputValue)
const handleClear = () => { emit('update:modelValue', ''); emit('change', ''); emit('clear') }
// password
let passwordVisible = ref(false)
const handlePassword = () => { passwordVisible.value = !passwordVisible.value; focus() }
const focus = () => { input.value.focus(); setTimeout(() => { input.value.setSelectionRange(-1,-1) }) } // 点击密码后自动对焦并焦点至为最后一位
// limit
const textLength = computed(() => String(props.modelValue).length)
const { baseStyleObject } = useNeumorphism(props)
let styleObject = computed(() => ({
'--font-size': `${props.size-26}px`, '--line-height': `${props.size-20}px`, '--limit-size': `${props.size-28}px`
}))
</script>
<template>
<div
class="san-input neumorphism flex"
:class="[{
'is-disabled': disabled,
}]"
:style="{...baseStyleObject,...styleObject}"
@mouseenter="hovering = true"
@mouseleave="hovering = false">
<!-- 前置内容 -->
<i v-if="preIcon" :class="[preIcon, 'iconfont']"></i>
<!-- 主体内容 -->
<input
v-if="type !== 'textarea'"
ref="input"
:value="modelValue"
v-bind="$attrs"
:disabled="disabled"
:type="showPassword ? (passwordVisible ? 'text': 'password') : type"
@input="emit('update:modelValue', $event.target.value)"
@focus="handleFocus"
@blur="handleBlur"
@change="emit('change', $event.target.value)"
/>
<textarea
v-else
ref="textarea"
:value="modelValue"
v-bind="$attrs"
:disabled="disabled"
@input="emit('update:modelValue', $event.target.value)"
@focus="handleFocus"
@blur="handleBlur"
@change="emit('change', $event.target.value)"
/>
<!-- 后置内容 -->
<span class="limit" v-if="$attrs.maxlength">{{textLength}}/{{$attrs.maxlength}}</span>
<i v-if="showClear" class="iconfont san-qingchu" @click="handleClear"></i>
<template v-if="showPassword">
<i v-if="!passwordVisible" class="iconfont san-bukejian" @click="handlePassword"></i>
<i v-if="passwordVisible" class="iconfont san-kejian" @click="handlePassword"></i>
</template>
<i v-if="postIcon" :class="[postIcon, 'iconfont']"></i>
</div>
</template>
<script>
export default {
name: 'sanorin-input',
}
</script>
<style scoped>
@import "../../style/index.css";
@import "../../style/neumorphism.css";
.san-input{
width: 250px;
padding: 10px;
border-radius: 5px;
}
.san-input > input{
flex: 1;
width: 220px;
background: transparent;
border: none;
outline: none;
padding: 0px;
font-size: var(--font-size);
line-height: var(--line-height);
}
.limit{
/* color: ; */
font-size: var(--limit-size);
}
.san-input > textarea{
flex: 1;
background: transparent;
border: none;
outline: none;
}
</style>