问题描述

在我们的印象中,v-model的用法好像就是绑定一个data中的数据(比如输入框)。比如下面的常见用法:

<el-input v-model="input" placeholder="请输入内容"></el-input>

<script>
export default {
  data() {
    return {
      input: ''
    }
  }
}
</script>

这样就会给我们造成一个错觉,好像v-model就是绑定一个数据字符串。其实v-model不仅可以绑定字符串,还可以结合v-for绑定数组。如下面的用法:

<template>
  <div id="app">
    <!-- 这里v-model动态绑定inputArr下的value -->
    <el-input 
      v-model="item.value" 
      placeholder="请输入内容" 
      v-for="(item,index) in inputArr" 
      :key="index"
    ></el-input>
  </div>
</template>

<script>
export default {
  data() {
    return {
      inputArr:[
        {
          value:"",
        },
        {
          value:"",
        },
        {
          value:"",
        },
      ]
    };
  },
};
</script>

结合vue的调试工具看一下数据双向绑定的效果图:
image.png

需求如下

下图中的这个效果图,就用到了v-model绑定数组的用法。
image

需求分析

有一个表单,作品项中默认有两个输入框,当点击增加作品按钮时,可以新增输入框。新增输入框的左边有一个可以删除的小图标(也就是从第三个输入框开始),点击删除小图标,就可以把对应的输入框删除掉。当然表单中的输入框都是必填项。没填写就做一个提示吧。

思路分析

首先是要放一个el-form的结构。下面的作品项el-form-item中的el-input通过v-for循环bookArr同时v-model绑定数组中的每一项的value。至于删除小图标,也一并写好,只不过第一个和第二个输入框不显示,也就是v-show判断一下,当index为0或者为1的时候隐藏。当点击增加作品时,往bookArr中输增加一项,当点击删除小图标时,根据删除的哪一项的索引,通过splice方法从第i个位置,删除1项。当然点击确认的时候要看看输入框内容是否为空,为空就提示一下,要是输入框全部都填写了,就可以使用输入框的参数作为参数发请求发给后台了了。

代码步骤

html部分

<template>
  <div id="app">
    <div class="content">
      <div class="contentHeader">
        <span>新增作家信息</span>
        <i class="el-icon-close"></i>
      </div>
      <div class="contentBody">
        <el-form ref="form" :model="form" label-width="80px">
          <el-form-item label="名字:">
            <el-input 
              v-model.trim="form.name"
              placeholder="请输入作家姓名"
            ></el-input>
          </el-form-item>
          <el-form-item label="作品:">
            <!-- 这个div里面的是细节重点 -->
            <div class="itemitem" v-for="(item, index) in bookArr" :key="index">
              <!-- 删除小图标 -->
              <i 
                v-show="show(index)"
                @click="deleteItem(index)"
                class="el-icon-remove-outline dingwei"
              ></i>
              <!-- 输入框v-model绑定数组 -->
              <el-input 
                v-model.trim="item.value"
                placeholder="请输入作家著作"
              ></el-input>
            </div>
            <el-button type="text" size="small" @click="addBook"
              >+增加作品</el-button
            >
          </el-form-item>
        </el-form>
      </div>
      <div class="contentFooter">
        <el-button size="small">取消</el-button>
        <el-button size="small" type="primary" @click="getFormValue">确认</el-button>
      </div>
    </div>
  </div>
</template>

js部分

<script>
export default {
  data() {
    return {
      form: {
        name: "",
      },
      bookArr: [
        {
          value: "",
        },
        {
          value: "",
        },
      ],
    };
  },
  methods: {
    // 添加一项
    addBook() {
      this.bookArr.push({ value: "" });
    },
    // 从第三项开始才展示
    show(i){
      if(i==0 | i==1){
        return false
      }else{
        return true
      }
    },
    // 根据索引删除对应哪一项
    deleteItem(i){
      this.bookArr.splice(i,1)
    },
    // 点击确认按钮
    getFormValue(){
      if(this.form.name == ""){
        this.$message.error('作家名字为必填项');
        return
      }
      // 这里也可以用数组的every方法做判断
      let num = 0
      this.bookArr.forEach((item)=>{
        if(item.value == ""){
          num = num + 0
        }else{
          num = num + 1
        }
      })
      // 当num等于this.bookArr.length的时候,说明都填写了
      if(num == this.bookArr.length){
        this.form.bookArr = this.bookArr
        console.log("发请求",this.form);
      }else{
        this.$message.error('作家作品需全部填写');
      }
    }
  },
};
</script>

css部分

<style lang="less" scoped>
#app {
  width: 100%;
  height: 100vh;
  background-color: rgba(0, 0, 0, 0.3);
  display: flex;
  justify-content: center;
  align-items: center;
  .content {
    width: 480px;
    height: 360px;
    background-color: #fff;
    border-radius: 5px;
    .contentHeader {
      width: 100%;
      height: 50px;
      border-bottom: 1px solid #e9e9e9;
      box-sizing: border-box;
      padding: 0 25px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      span {
        font-size: 20px;
      }
      i {
        font-size: 25px;
        cursor: pointer;
      }
    }
    .contentBody {
      overflow-y: auto;
      width: 100%;
      height: calc(100% - 100px);
      display: flex;
      justify-content: center;
      padding-top: 20px;
      box-sizing: border-box;
      padding-right: 25px;
      // align-items: center;
      .el-form {
        .itemitem {
          display: flex;
          align-items: center;
          position: relative;
          .dingwei {
            position: absolute;
            left: -30px;
            top: 12px;
          }
          i {
            font-size: 20px;
            margin-right: 6px;
          }
          .el-input {
            margin-bottom: 8px;
            width: 206px;
          }
        }
      }
    }
    .contentFooter {
      width: 100%;
      height: 50px;
      line-height: 50px;
      border-top: 1px solid #e9e9e9;
      text-align: center;
    }
  }
}
</style>

总结

好记性不如烂笔头,记录一下吧。如果本篇文章的思路帮助到您了,欢迎各位看官大佬们赏赐个赞吧。手动比心


水冗水孚
1.1k 声望585 粉丝

每一个不曾起舞的日子,都是对生命的辜负