Vue3基于Ant Design of Vue 2通过Composition API封装动态输入框组件

1,032 阅读2分钟

动态输入框组件

一、安装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>

三、功能实现思路

  1. 动态输入框总分为四个部分
  • 内容输入框
  • 数量输入框
  • 删除当前行按钮
  • 增加下一行按钮
  1. 分别通过组件库中组件构建起来
  • a-input
  • a-input-number
  • a-button && MinusOutlined
  • a-button && PlusOutlined
  1. 通过data数组存储每行的数据
//data数据结构
[
    //第一行
  {
    "name": "111",
    "count": 1
  },
   //第二行
  {
    "name": "2222",
    "count": 3
  }
]

  1. 通过data数组遍历每一行
  • 删除当前行按钮 每一行都显示
  • 增加下一行按钮 最后一行显示
  1. 通过自动获取焦点聚焦最新增加的输入框
  2. 通过失去焦点判断内容无输入自动删除输入框

四、完整源代码

  1. 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>


  1. 在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,
    }
}

  1. 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…

本文演示视频:点击浏览

更多前端内容欢迎关注公众号:天小天个人网