对原始的input标签封装成组件

82 阅读3分钟

vue3

策略:一步一步来分析,可直接看最后的两个组件代码

菜鸟学习之路,大佬多指正

两个组件:父组件和my-input组件

我需要封装一个最原始的子组件

// my-input组件
<template>
   <input type="text">
</template><script></script>
​
​
//父组件
<template>
     <div>其它</div>
   <my-input/>
    <div>其它</div></template><script>
import myInput from '...'
</script>

我现在需要一个可以在父组件中更改myInput的type的值(比如text或者password)(肯定不要与原有的input元素的属性不一致)

//父组件
<template>
     <div>其它</div>
   <my-input :type='password'/>
    <div>其它</div></template><script>
import myInput from '...'
</script>

既然你给我这个myInput组件传了一个type属性,那总得接收下吧

// my-input组件
<template>
   <input type="text">
</template><script setup>
const props = defineProps({
    type: 'text' | 'password',
})
</script>

好耶,现在我这个my-input组件有这个属性了,但是我好像没有用,还是写死的,对啊,我得给我的原始的input绑定上type

// my-input组件
<template>
   <input :type="type">
</template><script setup>
const props = defineProps({
    type: 'text' | 'password',
})
</script>

nice,现在终于实现了可以在父组件中控制my-input的类型了

其余均是类似的,就比如placeholder这个属性

接下来,让我们开始再进一步,来面对较为复杂的value属性

先了解:

通过 : 来向子组件传递props

  • 所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。

  • 另外,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。若你这么做了,Vue 会在控制台上向你抛出警告.(它是只读的啊) (ps:v-model绑定的是可以改的,底层实现的)

    image-20231215230352332

  • 也就是说,想要在子组件中进行更改,要不就是拿着这个值重新ref定义为另一个变量去使用或者就是computed对这个基础值做转换(本质都不会更改原始的值)image-20231215230916965

//父组件
<template>
     <div>其它</div>
   <my-input :type='password' :value="content"/>
    <div>其它</div></template><script>
import myInput from '...'
import {ref} from 'vue'
    const content=ref('你好')
</script>

然后就是刚刚提到是只读的,所以如果就是要修改props中的value就不能通过单纯的赋值操作

那就通过父组件事件监听,子组件去触发事件并传参过去

//父组件
<template>
     <div>其它</div>
   <my-input :type='password' @changeValue="changeValue" :value="content"/>
    <div>其它</div></template><script>
import myInput from '...'
import {ref} from 'vue'
    const content=ref('你好')
    const changeValue=(value)=>{
content=value
    }
</script>
// my-input组件
<template>
   <input :type="type" @input="onInput">
</template><script setup>
const props = defineProps({
    type: 'text' | 'password',
})
const emit = defineEmits(['changeValue'])
const onInput=(e)=>{
emit('changeValue',e.target.value)
}
</script>

这样确实可以实现子向父的通信,但我还需要挂一个事件啊.我想要一个效果是直接就可以在子组件中实现这个值的更新,并且传过去. 那有没有办法默认给其挂一个事件呐

让我们来看看官方

image-20231216003245873

这不就是我想要的答案吗?用v-model就会默认绑定一个事件,我只需要在my-input中触发就好了

//父组件
<template>
     <div>其它</div>
   <my-input :type='password' v-model:value="content" />  //有的同学可能问为什么加个:value就是上面的图的原因,不加默认的属性名字叫model-value
    <div>其它</div></template><script>
import myInput from '...'
import {ref} from 'vue'
    const content=ref('你好')
   
</script>
// my-input组件
<template>
   <input :type="type" :value="value" @input="onInput">
</template><script setup>
const props = defineProps({
    type: 'text' | 'password',
})
const emit = defineEmits(['update:value'])
const onInput=(e)=>{
 emit('update:value', e.target.value)
}
</script>

okok,再加点样式就差不多了,截止现在就可以实现简单的封装input组件了 image-20231216010641738.png