动态输入框组件
一、安装Ant Design of Vue
首先新建vue3.0的步骤就不赘述,网上有很多相关文章,直接开始安装依赖,安装好后请注意引入项目,具体可参考Ant Design of Vue 2.0官方文档。
//默认安装命令 v2可安不上
npm install ant-design-vue --save
//检查版本如果不是v2 可执行升级
npm i --save ant-design-vue@next
//main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
//ant-design-vue 组件库
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
const app = createApp(App);
app.use(router);
app.use(Antd);
app.mount('#app');
二、新建文件夹和文件
在components新建DynamicInput目录
//路径:src/components/DynamicInput
在DynamicInput新建js目录
//路径:src/components/DynamicInput/js
在DynamicInput下js目录新建index.ts
//路径:src/components/DynamicInput/js/index.ts
在DynamicInput新建index.vue文件
//路径:src/components/DynamicInput/index.vue
DynamicInput下的index.vue基础结构
//src/components/DynamicInput/index.vue
<template>
<a-row>
</a-row>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
export default defineComponent({
components:{},
props:{},
emits: [],
setup(){
return {
}
}
})
</script>
<style scoped>
</style>
新建src/view/DynamicInputPage.vue
//src/vie/DynamicInputPage.vue
<template>
<div>
<DynamicInput/>
</div>
</template>
<script>
import DynamicTags from '@/components/DynamicInput/index.vue'
export default {
components:{
DynamicInput,
}
}
</script>
<style scoped>
</style>
三、功能实现思路
- 动态输入框总分为四个部分
- 内容输入框
- 数量输入框
- 删除当前行按钮
- 增加下一行按钮
- 分别通过组件库中组件构建起来
- a-input
- a-input-number
- a-button && MinusOutlined
- a-button && PlusOutlined
- 通过data数组存储每行的数据
//data数据结构
[
//第一行
{
"name": "111",
"count": 1
},
//第二行
{
"name": "2222",
"count": 3
}
]
- 通过data数组遍历每一行
- 删除当前行按钮 每一行都显示
- 增加下一行按钮 最后一行显示
- 通过自动获取焦点聚焦最新增加的输入框
- 通过失去焦点判断内容无输入自动删除输入框
四、完整源代码
- DynamicInput下的index.vue
//src/components/DynamicInput/index.vue
<template>
<div class="container">
<a-space direction="vertical" ref="inputBoxDom" style="width: 100%" v-if="data.length>0">
<a-row class="item-row" :gutter="20" v-for="(item,index) in data" :key="index">
<a-col :span="16">
<a-input :maxLength="20" v-model:value="item.name" @blur="inputBlur(item,index)"/>
</a-col>
<a-col :span="4">
<a-input-number :min="1" v-model:value="item.count" />
</a-col>
<a-col :span="4">
<a-space>
<a-button type="danger" shape="circle" @click="ItemInputDelBtn(index)">
<template #icon><MinusOutlined /></template>
</a-button>
<a-button type="primary" shape="circle" v-if="index+1==data.length" @click="ItemInputAddBtn(index)">
<template #icon><PlusOutlined /></template>
</a-button>
</a-space>
</a-col>
</a-row>
</a-space>
<a-tag v-else @click="addInput">
<plus-outlined/> 添加内容
</a-tag>
</div>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import {PlusOutlined,MinusOutlined} from '@ant-design/icons-vue';
import dynamicInput from './js/index';
export default defineComponent({
components:{
PlusOutlined,
MinusOutlined
},
emits:['change'],
setup(props,context){
const {
inputBoxDom,
data,
addInput,
ItemInputAddBtn,
ItemInputDelBtn,
inputBlur,
} = dynamicInput(props,context);
return {
inputBoxDom,
data,
addInput,
ItemInputAddBtn,
ItemInputDelBtn,
inputBlur,
}
}
})
</script>
<style scoped>
</style>
- 在DynamicInput下js目录新建index.ts
//路径:src/components/DynamicInput/js/index.ts
import {ref,toRaw,watch,nextTick} from 'vue'
import { message } from 'ant-design-vue';
export default function dynamicInput(props: any,context: any) {
const inputBoxDom: any = ref(null);
const data = ref<object[]>([]);
//添加输入
const addInput = ()=>{
data.value.push({
name:'',
count:1,
});
//自动聚焦输入框
nextTick(() => {
const dom = inputBoxDom.value;
const lastIndex = dom.$el.children.length-1;
console.log(dom.$el.children[lastIndex].getElementsByClassName("ant-input")[0].focus());
});
};
//输入框失去焦点
const inputBlur = (item: any,index: number)=>{
if(!item.name || !item.name.trim()){
message.config({
maxCount:1,
});
message.error('请输入内容');
data.value.splice(index,1);
return false;
}
return true;
};
//输入框添加按钮
const ItemInputAddBtn = (index: number)=>{
if(inputBlur(data.value[index],index)){
data.value.push({
name:'',
count:1,
});
}
//自动聚焦输入框
nextTick(() => {
const dom = inputBoxDom.value;
const lastIndex = dom.$el.children.length-1;
console.log(dom.$el.children[lastIndex].getElementsByClassName("ant-input")[0].focus());
});
};
//输入框删除按钮
const ItemInputDelBtn = (index: number)=>{
data.value.splice(index,1);
};
watch(data.value, (newValue: any, oldValue: any) => {
context.emit('change',toRaw(newValue))
});
return {
inputBoxDom,
data,
addInput,
ItemInputAddBtn,
ItemInputDelBtn,
inputBlur,
}
}
- src/view/DynamicInputPage.vue
//src/view/DynamicInputPage.vue
<template>
<div class="container">
<div class="formBox">
<DynamicInput @change="inputChange" />
</div>
<div class="jsonCode">
<pre>{{jsonData}}</pre>
</div>
</div>
</template>
<script>
import {ref} from 'vue'
import DynamicInput from '@/components/DynamicInput/index.vue'
export default {
components:{
DynamicInput,
},
setup(){
const jsonData = ref([]);
const inputChange = e=>{
jsonData.value = e;
console.log(e)
};
return{
jsonData,
inputChange
}
}
}
</script>
<style scoped>
.container{
display: flex;
box-sizing: border-box;
margin: 0 auto;
padding: 20px 10px;
width: 100%;
max-width: 1200px;
}
.formBox{
width: 50%;
max-width: 600px;
}
.jsonCode{
box-sizing: border-box;
padding: 20px;
width: 50%;
max-width: 600px;
min-height:200px;
background: #333;
color: #fff;
}
</style>
项目源代码:github.com/jiangzetian…
本文演示视频:点击浏览
更多前端内容欢迎关注公众号:天小天个人网