功能分析
1 .可以使用v-model实现数据的双向绑定,组件里面绑定v-model
2 .支持style改变输入框的宽度,如果小于某一个值的话,当输入内容特别多的时候,上面开启一个显示输入内容的信息框
3 .加一个清空按钮,可以添加图标-search输入框,或者是一般人物信息的输入框
4 .可以变成textarea
5 .前面和后面都有自动补充内容的选项,比如163邮箱,或者输入网站的时候
6 .下方提供历史记录,推荐搜索词汇
7 .如果没有选择历史记录,当玩家输入的时候,给自动补全
8 .玩家返回的信息要做本地缓存,这样再次请求的时候直接返回缓存(适用于特定业务)
9 .输入框可以设置只读
10 .最大输入长度
11 .对输入的内容进行正则验证 加在那个的onBlur事件下面,取消焦点的时候进行验证
12 .还要提供事件绑定,给组件
13 .事件触发的代码
14 .icon的显示要变成slot方式。用slot的地方这么多
15 .长度限制
16 .并不需要限制输入数字的类型,不知道之前为什么要加这个
17 .密码框要显示隐藏
18 .textarea根据输入自适应高度
19 .复合输入框
1 .通过前置和后置的slot可以实现复合型的输入框
2 .也就是前后各有一个下拉选择框。进行一些自动补全
3 .看源码实现这个dom结构,这种的都是必须slot传入整个组件选择组件。
4 .依照golang的设计哲学,我们需要的而是组合而不是继承,那写组件的实质也是希望组合这个东西
5 .所以我们完全可以在原来的select组件上面进行扩展,让他多一个左边不全的样式,右边补全的样式。这样写源码的时候其实不用考虑这么多,其实使用的时候是分开使用的。然后把前面不全和后面不全的值传到这个组件里面,统一的输出都是走这个组件
6 .既然是写组件,为什么不在拆分的更彻底一点呢。
7 .这样的话slot的插槽其实只是用来添加icon的一个用处了。。
9 .之前的还是会和notice组件进行联动,比如各种弹得提示,或者其他的辅助提示
10 .在进一步拆分,icon是否能拆分。。
11 .发现的bug
20 .结合Poptip组件,实现一个数值输入框,方便内容超长时的全景展现
handleBlur () {
this.$emit('on-blur');
this.$dispatch('on-form-blur', this.value);
},
//dispatch了解一下
最核心的还是组件里面加上v-model操作
1 .这个竟然都没有实现
2 .其实核心就是当使用组件的时候使用v-model 进行操作的话
3 .父对子
1 .子组件自动接收这个参数,上面v-model所绑定的数据如果外面改的话,里面也会改变
value:{
type:[String,Number],
default:function(){
return null
}
}
//可以做一些清空操做
4 .子对父
1 .this.$emit('input',this.inputValue)
//当需要把里面修改的数据传递到外面的时候,就走这个逻辑
Input组件使用的时候传入slot插槽,不能正确触发里面组件的input事件
1 .使用的代码
<InputP size="small" v-model="value">
777
</InputP>
//将777作为默认插槽传入,其实是想传一些图标组件
2 .代码
<template>
<div :class="wrapClasses">
<div v-if="type!=='textarea'">
<div v-if="computedPreappend" class="li-input-preappend">
<slot name="preappend"></slot>
</div>
<input
ref="input"
:id="elementId"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
:class="inputClass"
:placeholder="placeholder"
:disabled="disabled"
:maxlength="maxlength"
:readonly="readonly"
:value="currentValue"
:number="number"
:name="name"
:autofocus="autofocus"
:type="currentType"
@keyup.enter="handleEnter"
@keyup="handleKeyup"
@keypress="handleKeypress"
@keydown="handleKeydown"
@focus="handleFocus"
@blur="handleBlur"
@input="handleInput"
@change="handleChange"
>
<div v-if="computedAppend" class="li-input-append">
<span v-if="showWordLimit">{{textLength/upperLimit}}</span>
<slot name="append"></slot>
</div>
<slot>default</slot>
</div>
<div v-else>
<textarea></textarea>
<span v-if="showWordLimit"></span>
</div>
</div>
</template>
<script>
const pre ="li-input"
export default {
name:"Input",
props:{
type:{
validator(value){
return ["text","textarea","password","url","email","data","number","tel"].includes(value)
},
default:"text",
},
value:{
type:[String,Number],
default:'',
},
size:{
validator(value){
return ["small","large","default"].includes(value)
},
default:"default"
},
placeholder:{
type:String,
default:"",
},
maxlength:{
type:[Number,String]
},
disabled:{
type:Boolean,
default:false,
},
autosize:{
type:[Boolean,Object],
default:false,
},
// textarea下有效,自适应高度
rows:{
type:Number,
default:2,
},
readonly:{
type:Boolean,
default:false,
},
// 限制只读
name:{
type:String,
},
Number:{
type:Boolean,
default:false,
},
autofocus:{
type:Boolean,
default:false,
},
autocomplete:{
type:String,
default:"off",
},
elementId:{
type:String,
},
wrap:{
validator(value){
return ["hadr","soft"].includes(value)
}
},
showWordLimit:{
type:Boolean,
default:false,
},
password:{
type:Boolean,
default:false,
},
spellcheck:{
type:String,
default:"spellcheck"
}
},
data(){
return {
currentValue:this.value,
showPassword:false,
number:''
}
},
computed:{
wrapClasses(){
return [
`${pre}-wrapper`,
{
// [`${pre}-wrapper-${this.size}`]:!!this.size,
[`${pre}-type-${this.type}`]:this.type,
}
]
// 父级样式
},
inputClass(){
return [
`${pre}`,
{
[`${pre}-${this.size}`]:this.size,
[`${pre}-disabled`]:this.disabled,
}
]
// input样式
// 决定大小
},
currentType(){
let type=this.type
if(type==="password"&&this.password&&this.showPassword){
type="text"
}
return type
},
computedAppend(){
let state=false;
// if(this.type!=="textarea"){
// if(this.$slots.append!==undefined){
// state=true
// }else{
// state=false
// }
// }
// console.log(state)
// return state;
return true
},
computedPreappend(){
let state=false;
// if(this.type!=="textarea"){
// if(this.$slots.preappend!==undefined){
// state=true
// }else{
// state=false
// }
// }
// return state
return true
},
textLength(){
if (typeof this.value=="number"){
return String(this.value).length
}
return (this.value||"").length
},
upperLimit(){
return this.maxlength
}
},
methods:{
handleEnter(event){
this.$emit("on-enter",event)
if(this.search) this.$emit("on-search",this.currentType)
},
handleKeydown(event){
this.$emit("on-keydown",event)
},
handleKeypress(event){
this.$emit("on-keypress",event)
},
handleKeyup(event){
this.$emit("on-keyup",event)
},
handleFocus(event){
this.$emit("on-focus",event)
},
handleBlur(event){
this.$emit("on-blur",event)
},
handleInput(event){
let value=event.target.value
this.$emit("input",value)
//这样使用的时候这里的事件触发是有点问题滴
console.log("handleInput",event.target.value)
},
handleChange(event){
console.log('handle change')
this.$emit("on-input-change",event)
},
setCurrentValue(value){
if(value==this.currentType)return;
this.$nextTick(()=>{
this.resizeTextarea();
})
this.currentValue=value
},
handleComposition(event){
console.log("handleComposition")
}
}
,
watch:{
value(o,n){
console.log(n)
}
}
}
</script>
<style lang="less" src="./inputP.less">
</style>
1 .解决方法,在里面的input部分加一个内部的v-model属性,然后最后输出的时候操作整体返回这个属性
2 .层级关系是怎么决定的,为什么他按照顺序,后面的样式就能覆盖前面的样式,我这就不行。样式表中,谁的在后面就用谁的,并不是class里面的排序
3 .v-else,v-else-if必须紧紧的连在一起,中间不能有任何dom元素
4 .他之前的会包括很多type类型,数字,电话号码,邮箱,日期,但是很多都是没有效果的。这里统一改成密码,数字,字符串这三个类型,别的都写各自的组件吧
原来写的input组件的优点
1 .第一次就是看了下他怎么写,然后就自己写了。走出了自己的一条路,联系业务
2 .第二次一行一行的看源码。然后在写的时候需要加一些东西
3 .数字组件的时候:限制大小,限制小数点
4 .提示语太长还会省略.升级版就是上方有提示组件的那个
5 .input的事件还会根据组件的类型进行判断,结合notice组件进行表格填写的提示
6 .