IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue_计算属性_监听器_品牌管理案例 -> 正文阅读

[JavaScript知识库]Vue_计算属性_监听器_品牌管理案例

v-for更新监测

<template>
  <div>
    <ul>
      <li v-for="(val, index) in arr" :key="index">
        {{ val }}
      </li>
    </ul>
    <button @click="revBtn">数组翻转</button>
    <button @click="sliceBtn">截取前3个</button>
    <button @click="updateBtn">更新第一个元素值</button>
  </div>
</template>

<script>
// 总结: 哪些方式会导致v-for更新
// 1. 翻转数组 可以
// 2. 截取数组 不可以
// 3. 单独字面量修改 不可以, 数组方法修改 可以
// 4. 数组整个被重新赋值, 可以

// 总结:
// 除了字面量[下标]方法以外的, "只要改变原数组"都会导致v-for更新
export default {
  data() {
    return {
      arr: [5, 3, 9, 2, 1],
    };
  },
  methods: {
    revBtn() {
      // 情况1. 数组翻转 arr
      this.arr.reverse();
    },
    sliceBtn() {
      // 情况2: 截取前3个
      let newArr = this.arr.slice(0, 3);
      this.arr = newArr;  // 会导致原数组更新
    },
    updateBtn() {
      // 情况3: 更新第一个元素值
      // this.arr[0] = 100
      this.arr.splice(0, 1, 100);  // 替换原数组导致更新
      // Vue还提供了内置 $set方法
      // this.$set(this.arr, 0, 100)  // 了解
    },
  },
};
</script>

<style>
</style>

v-for如何更新的

<template>
  <div>
    <ul>
      <li v-for="(val, ind) in arr" :key="ind">
        {{ val }}
      </li>
    </ul>
    <button @click="btn">下标1位置插入新来的</button>
  </div>
</template>

<script>
// 总结: v-for 到底如何更新的?
// 1. 第一次v-for, 准备一套DOM结构, 渲染到页面上
// 2. v-for 检测到目标结构变化, 再生成新的DOM结构, 和原来的DOM结构做对比, 只改变有差异的部分
// 3. 尽可能原地复用现有的标签
export default {
  data(){
    return {
      arr: ['老大', "老二", '老三']
    }
  },
  methods: {
    btn(){
      this.arr.splice(1, 0, '新来的')
    }
  }
}
</script>

<style>

</style>

key作用

<template>
  <div>
    <ul>
      <li v-for="obj in arr" :key="obj.id">
        {{ obj.name }}
      </li>
    </ul>
    <button @click="btn">下标1位置插入新来的</button>
  </div>
</template>

<script>
// 目标: key作用
// 无key属性, 和有key(值为索引), v-for更新时, (就地复用标签, 对比差异, 只更新变化的)
// 2. 有key(值为id), v-for更新时, 用key来对比新旧DOM, 会提高'更新'的性能
// key值要求: 唯一不重复, 数字或字符串
// 结论:
// (1): key属性提高更新时, 性能, dom变化后用key来做对比找出差异更新真实DOM
// (2): key的值要么用id, 没有id用索引值
export default {
  data() {
    return {
      arr: [
        {
          name: '老大',
          id: 50
        },
        {
          name: '老二',
          id: 31
        },
        {
          name: '老三',
          id: 10
        }
      ],
    };
  },
  methods: {
    btn(){
      this.arr.splice(1, 0, {
        id: 19, 
        name: '新来的'
      })
    }
  }
};
</script>

<style>
</style>

动态class

<template>
  <div>
    <!-- 语法: :class="{类名: 布尔值}" -->
    <p :class="{redStr: true}">我是p标签, 尝试动态class的样式</p>
  </div>
</template>

<script>
// 目标: 动态class
// 语法: :class="{类名: 布尔值}"
// 效果: 布尔值为true, 类名原地生效, 为false,不生效
export default {

}
</script>

<style>
.redStr{
  color: skyblue;
}
</style>

动态style

<template>
  <div>
    <!-- 语法: :style="{css属性名: 值}" -->
    <p style="color: red; backgroundcolor: pink">111</p>
    <p :style="{ color: 'yellow', backgroundColor: 'skyblue' }">
      我是p标签, 尝试动态style的样式
    </p>
  </div>
</template>

<script>
// 目标: 动态class
// 场景: 样式值会变, 需要采用动态style
// 语法: :style="{样式名: 样式值}"
export default {};
</script>

<style>
</style>

vue计算属性-computed

<template>
  <div>
    <p>和为: {{ num }}</p>
  </div>
</template>

<script>
// 目标: 计算属性
// 作用(场景): 当一个变量的值, 通过其他变量计算而得来的
// 语法:
/**
 * computed: {
 *   计算属性名(){  // 它也是一个变量(所以不能和data里重名)
 *    // 必须return 值, 给这个计算属性使用
 *   }
 * }
 */
// 效果: 计算属性里引用的变量发生值后, 重新执行计算属性函数里代码
export default {
  data() {
    return {
      a: 10,
      b: 8,
    };
  },
  computed: {
    num() {
      return this.a + this.b;
    },
  },
};
</script>

<style>
</style>

vue计算属性-缓存

<template>
  <div>
    <p>{{ reverseMessage }}</p>
    <p>{{ reverseMessage }}</p>
    <p>{{ reverseMessage }}</p>
    <p>{{ getMessage() }}</p>
    <p>{{ getMessage() }}</p>
    <p>{{ getMessage() }}</p>
  </div>
</template>

<script>
// 目标: 计算属性'缓存'好处
// 好处: 计算属性有'缓存', 第一次计算结果后保存在内存当中, 当第二次使用时(值未发生过变化), 直接取值使用(不会调用函数)
// 当计算属性内使用变量值发生改变, 计算属性会从新算一次并缓存
export default {
  data() {
    return {
      message: "Hello World",
    };
  },
  computed: {
    reverseMessage() {
      console.log("计算属性 - 函数执行了");
      return this.message.split("").reverse().join("");
    },
  },
  methods: {
    getMessage() {
      console.log("methods - 函数执行了");
      return this.message.split("").reverse().join("");
    },
  },
};
</script>

<style>
</style>

vue计算属性-完整写法

<template>
  <div>
    <!-- 表单value属性的值 和 vue变量的值 双向绑定 -->
    <input type="text" v-model="full" />
  </div>
</template>

<script>
// 目标: 计算属性完整写法
// 前提: 你要给计算属性, 赋值, 才使用'完整写法'
// 语法:
/**
 * 只要返回值
   computed: {
      计算属性名(){
          return 值
   }
 }
 完整写法
    computed: {
      计算属性名:{
        set(){},  // 有人给计算属性变量'赋值'的时候,自动触发此函数
        get(){}  // 有人要'使用'计算属性变量值得时候, 自动触发此函数并必须return值
   }
 }
 */
export default {
  computed: {
    // full(){
    //   return '你好啊'
    // }
    full: {
      set(val) {
        // 页面改变 -> set触发
        console.log(val);
      },
      get() {
        return "翟潇闻";
      },
    },
  },
};
</script>

<style>
</style>

案例-全选和反选

<template>
  <div>
    <span>全选:</span>
    <input type="checkbox" v-model="isAll" />
    <button @click="fanFn">反选</button>
    <ul>
      <li v-for="(obj, index) in arr" :key="index">
        <input type="checkbox" v-model="obj.c" />
        <span>{{ obj.name }}</span>
      </li>
    </ul>
  </div>
</template>

<script>
// 需求1: 小选 -> 全选
// 1.0 准备标签和样式
// 1.1 铺设li了, '小选框选中状态, 和对象的c属性双向绑定'
// 1.2 全选框, 选中状态, 也需要通过小选框们统计而得来呀
// 1.3 全选框, 定义计算属性叫 isAll
// 1.4 用eveny方法统计小选框关联的数组里数据, 返回给isAll显示到页面上, 全选用v-model="isAll"

// 需求1: 全选 -> 小选
// 2.0 思考页面全选后, 同步给v-model的isAll变量
// 2.1 isAll改写成了完整写法(带set/get)
// 2.2 在set中, 页面全选选中状态, 触发set方法传入true/false
// 2.3 遍历arr数组里每个对象, 给每个小选框同步状态

// 需求3: 点击反选
// 3.0 反选 - 点击事件
// 3.1 遍历数组里每个对象, 把对象的c属性取出, 取反, 在赋予回去
// 核心思想: 操作数据, 驱动视图(v-model关键选中状态)
export default {
  data() {
    return {
      arr: [
        {
          name: "猪八戒",
          c: false,
        },
        {
          name: "孙悟空",
          c: false,
        },
        {
          name: "唐僧",
          c: false,
        },
        {
          name: "白龙马",
          c: false,
        },
      ],
    };
  },
  methods: {
    fanFn() {
      this.arr.forEach((obj) => {
        obj.c = !obj.c;
      });
    },
  },
  computed: {
    isAll: {
      set(val) {
        // val变量值:(true/false)
        // 全选框选中状态值, 赋予给每个小选框选中状态
        this.arr.forEach((obj) => {
          obj.c = val;
        });
      },
      get() {
        // 所有符合条件的, 返回的是true
        // 有一个不符合条件的, 返回的是false
        return this.arr.every((obj) => obj.c === true);
      },
    },
  },
};
</script>

vue侦听器-watch

<template>
  <div>
    <input type="text" v-model="userName" />
  </div>
</template>

<script>
// 目标: 侦听某个变量'值'的改变
// 语法:
/**
   watch: {
      被侦听的变量名(newVal,oldVal){
        只要侦听的变量名值改变, 函数就会自动触发
   }
 }
 */
export default {
  data() {
    return {
      userName: "",
    };
  },
  watch: {
    userName(newVal, oldVal) {
      console.log(newVal, oldVal);
    },
  },
};
</script>

<style>
</style>

vue侦听器-深度侦听

<template>
  <div>
    <input type="text" v-model="user.name" />
    <input type="text" v-model="user.age" />
  </div>
</template>

<script>
// 目标: 侦听对象值得变化
// 语法:
/**
   watch: {
      被侦听的变量名{
        handler(newVal,oldVal){},
        deep: true  // 深度侦听
   }
 }
 */
// 原因: 变量里存的是对象(内存地址), 绑定失败, 改的是对象里面的属性值得改变, user本身并为发生变化
// 解决: 深度侦听
export default {
  data() {
    return {
      user: {
        name: "",
        age: 0,
      },
    };
  },
  watch: {
    // 如果非要拿到某个属性值新旧(了解)
    // ["user.age"]
    user: {
      handler(newVal, oldVal) {
        // newVal,oldVal 监听的user变量的值(本身就是个对象)
        // 改变数据, 改的对象里的属性值, 对象本身并未修改(还是那个对象)
        console.log(newVal, oldVal);
      },
      deep: true, // 深度侦听
    },
  },
};
</script>

<style>
</style>

案例-品牌管理

<template>
  <div id="app">
    <div class="container">
      <!-- 顶部框模块 -->
      <div class="form-group">
        <div class="input-group">
          <h4>品牌管理</h4>
        </div>
      </div>

      <!-- 数据表格 -->
      <table class="table table-bordered table-hover mt-2">
        <thead>
          <tr>
            <th>编号</th>
            <th>资产名称</th>
            <th>价格</th>
            <th>创建时间</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="obj in list" :key="obj.id">
            <td>{{ obj.id }}</td>
            <td>{{ obj.name }}</td>

            <!-- 如果价格超过100,就有red这个类 -->
            <!-- :class="{类名: 布尔值}" -->
            <td :class="{ red: obj.price >= 100 }">{{ obj.price }}</td>
            <td>{{ formatDate(obj.time) }}</td>
            <td><a href="#" @click="delFn(obj.id)">删除</a></td>
          </tr>
          <tr style="background-color: #eee">
            <td>统计:</td>
            <td colspan="2">总价钱为: {{ allPrice }}</td>
            <td colspan="2">平均价: {{ svgPrice }}</td>
          </tr>
        </tbody>

        <tfoot v-if="list.length === 0">
          <tr>
            <td colspan="5" style="text-align: center">暂无数据</td>
          </tr>
        </tfoot>
      </table>

      <!-- 添加资产 -->
      <form class="form-inline">
        <div class="form-group">
          <div class="input-group">
            <input
              type="text"
              class="form-control"
              placeholder="资产名称"
              v-model="name"
            />
          </div>
        </div>
        &nbsp;&nbsp;&nbsp;&nbsp;
        <div class="form-group">
          <div class="input-group">
            <input
              type="number"
              class="form-control"
              placeholder="价格"
              v-model.number="price"
            />
          </div>
        </div>
        &nbsp;&nbsp;&nbsp;&nbsp;
        <!-- 阻止表单提交 -->
        <!-- form 里按钮阻止默认提交行为.prevent -->
        <button class="btn btn-primary" @click.prevent="addFn">添加资产</button>
      </form>
    </div>
  </div>
</template>

<script>
// 需求1: 铺设表格数据
// 1.0 md里复制标签和数据
// 1.1 下载bootstrap并main.js中引入
// 1.2 v-for把数据渲染到表格里
// 1.3 价格加动态 class, 价格>100才有red类名

// 需求2: 添加资产
// 2.0 按钮 - 点击事件 事件方法
// 2.1 v-model和变量, 收集输入框内容
// 2.2 判断是否为空, 给提示
// 2.3 数据添加到数组里(形成一个新的对象)
// 2.4 细节: form 里按钮阻止默认提交行为.prevent

// 需求3: 删除功能
// 3.0 删除a - 点击事件和方法
// 3.1 事件触发传递对应id值
// 3.2 通过id找对应索引
// 3.3 数组splice方法, 传入索引删除数组元素 -> 标签里使用list的地方就会重新计算
// 3.4 tfoot加v-if判断,无值在显示
// 3.5 删除光了以后, 在新增bug解决(因为数组里无值, 所以要判断)

// 需求4: 时间格式处理
// 4.0 (第一种方法自己写/第二种方法moment包处理时间格式化)
// 4.1 下载moment, 引入moment
// 4.2 methods里定义formatDate函数
// 4.3 上面时间处, 调用methods里方法, 传递要被处理时间
// 4.4 formatDate函数里处理后, 把结果返回到标签显示

// 需求5: 完成总价和均价的计算
// 5.0 准备一行tr标签
// 5.1 准备2个计算属性变量, 并在标签内使用
// 5.2 在计算属性内, 计算总价和均价并返回

// 需求6: 把数组数据, 缓存到浏览器本地(localStorage)
// 6.0 添加资产/删除资产, 侦听list数组改变, 把数组保存到本地
import moment from "moment";
export default {
  data() {
    return {
      name: "", // 名称
      price: 0, // 价格
      // list: [
      //   { id: 100, name: "外套", price: 199, time: new Date("2010-08-12") },
      //   { id: 101, name: "裤子", price: 34, time: new Date("2013-09-01") },
      //   { id: 102, name: "鞋", price: 25.4, time: new Date("2018-11-22") },
      //   { id: 103, name: "头发", price: 19900, time: new Date("2020-12-12") },
      // ],
      list: JSON.parse(localStorage.getItem("brandList")) || [], // 本地无值, 就给一个空数组(因为调用push方法)
    };
  },
  methods: {
    // 添加资产 - 点击事件
    addFn() {
      // 判断内容
      if (this.name.trim().length === 0 || this.price === 0) {
        alert("请输入内容");
        return; // 阻止代码往下继续执行
      }
      // 新增
      let theId =
        this.list.length === 0 ? 100 : this.list[this.list.length - 1].id + 1;
      this.list.push({
        id: theId,
        name: this.name,
        price: this.price,
        time: new Date(),
      });
      this.name = "";
      this.price = 0;
    },
    delFn(id) {
      // 通过要删除id, 找到对应下标, 才能用数组删除方法
      let index = this.list.findIndex((obj) => obj.id === id);
      this.list.splice(index, 1);
    },
    // 定义时间处理函数
    formatDate(dateObj) {
      return moment(dateObj).format("YYYY-MM-DD");
    },
  },
  computed: {
    allPrice() {
      // 遍历数组每个对象, 进行累加
      // 外面return 是把累加好的结果返回给allPrice使用
      // 里面return是把每次累加的sum值, 返回给下一次函数调用sum的初始值
      return this.list.reduce((sum, obj) => {
        sum += obj.price;
        return sum;
      }, 0);
    },
    svgPrice() {
      // toFixed保留两位小数
      return (this.allPrice / this.list.length).toFixed(2);
    },
  },
  watch: {
    list: {
      deep: true,
      handler() {
        // 只要list内发生改变, 此处就侦听到自动执行
        // 存到本地
        localStorage.setItem("brandList", JSON.stringify(this.list));
      },
    },
  },
};
</script>

<style >
.red {
  color: red;
}
</style>

作业1_买点书练习

<template>
  <div>
    <p>请选择你要购买的书籍</p>
    <ul>
      <li v-for="(obj, index) in arr" :key="index">
        <span>{{ obj.name }}</span>
        <button @click="buyFn(index)">买书</button>
      </li>
    </ul>
    <table border="1" width="500" cellspacing="0">
      <tr>
        <th>序号</th>
        <th>书名</th>
        <th>单价</th>
        <th>数量</th>
        <th>合计</th>
      </tr>
      <tbody>
        <tr v-for="(obj, index) in arr" :key="index">
          <td>{{ index + 1 }}</td>
          <td>{{ obj.name }}</td>
          <td>{{ obj.price }}</td>
          <td>{{ obj.count }}</td>
          <td>{{ obj.price * obj.count }}</td>
        </tr>
      </tbody>
    </table>
    <p>总价格为: {{ allPrice }}</p>
  </div>
</template>

<script>
// 目标: 目标: 把数据铺设到页面上, 当用户点击买书按钮, 书籍数量增加1, 并且要计算累计的和
// 1. 标签和数据
// 2. v-for循环li
// 3. v-for循环表格里数据
export default {
  data() {
    return {
      arr: [
        {
          name: "水浒传",
          price: 107,
          count: 0,
        },
        {
          name: "西游记",
          price: 192,
          count: 0,
        },
        {
          name: "三国演义",
          price: 219,
          count: 0,
        },
        {
          name: "红楼梦",
          price: 178,
          count: 0,
        },
      ],
    };
  },
  computed: {
    allPrice(){
      // 5. 统计总价
      return this.arr.reduce((sum, obj) => {
        sum += obj.price * obj.count
        return sum;
      }, 0)
    }
  },
  methods: {
    // 4. 修改索引对应 - 对象的count值
    buyFn(ind){
      this.arr[ind].count++
    }
  }
};
</script>

作业2_选你爱我求和

<template>
  <div>
    <!-- 无id时, 可以使用index(反正也是就地更新) -->
    <div style="display: inline-block" v-for="(num, index) in arr" :key="index">
      <!-- 4.用v-model收集用户选中的复选框对应的value值 -->
      <input type="checkbox" :value="num" v-model="listArr" />
      <span>{{ num }}</span>
    </div>
    <p>你选中的元素, 累加的值和为:{{ allCount }}</p>
  </div>
</template>

<script>
// 目标: 选择数字, 求和
// 1. 标签和数据准备好
// 2. v-for生成标签解构, 复选框绑定value值
export default {
  data() {
    return {
      arr: [9, 15, 19, 25, 29, 31, 48, 57, 62, 79, 87],
      listArr: [],
    };
  },
  // 3.计算属性
  computed: {
    allCount() {
      // 5. 统计listArr和
      return this.listArr.reduce((sum, num) => (sum += num), 0);
    },
  },
};
</script>

作用3_导航切换效果

<template>
  <div class="wrap">
    <div class="nav_left" id="navLeft">
      <div class="nav_content">
        <span
          :class="{ active: index === selIndex }"
          v-for="(obj, index) in arr"
          :key="obj.first_id"
          @click="btn(index)"
          >{{ obj.first_name }}</span
        >
      </div>
    </div>
    <div class="down">
      <i class="iconfont icon-xiajiantoubeifen gray"></i>
    </div>
  </div>
</template>

<script>
// 目标: 切换到移动端画面, 点击导航, 高亮
// 提示: 索引 / 高亮的class的样式
// 绑定点击事件, 传入对应索引
export default {
  data() {
    return {
      // 保存用户点击的频道的索引
      selIndex: 0,
      arr: [
        {
          first_id: "0",
          first_name: "热门",
        },
        {
          first_id: "621",
          first_name: "\u5496\u5561",
        },
        {
          first_id: "627",
          first_name: "\u996e\u98df",
        },
        {
          first_id: "279",
          first_name: "\u7537\u88c5",
        },
        {
          first_id: "294",
          first_name: "\u5973\u88c5",
        },
        {
          first_id: "122",
          first_name: "\u773c\u955c",
        },
        {
          first_id: "339",
          first_name: "\u5185\u8863\u914d\u9970",
        },
        {
          first_id: "391",
          first_name: "\u6bcd\u5a74",
        },
        {
          first_id: "35",
          first_name: "\u978b\u9774",
        },
        {
          first_id: "39",
          first_name: "\u8fd0\u52a8",
        },
        {
          first_id: "153",
          first_name: "\u7bb1\u5305",
        },
        {
          first_id: "119",
          first_name: "\u7f8e\u5986\u4e2a\u62a4",
        },
        {
          first_id: "355",
          first_name: "\u5bb6\u7eba",
        },
        {
          first_id: "51",
          first_name: "\u9910\u53a8",
        },
        {
          first_id: "334",
          first_name: "\u7535\u5668",
        },
        {
          first_id: "369",
          first_name: "\u5bb6\u88c5",
        },
        {
          first_id: "10",
          first_name: "\u5bb6\u5177",
        },
        {
          first_id: "223",
          first_name: "\u6570\u7801",
        },
        {
          first_id: "429",
          first_name: "\u6c7d\u914d",
        },
        {
          first_id: "546",
          first_name: "\u5065\u5eb7\u4fdd\u5065",
        },
        {
          first_id: "433",
          first_name: "\u5b9a\u5236",
        },
      ],
    };
  },
  methods: {
    btn(theIndex) {
      // 用户点的索引保存一下
      this.selIndex = theIndex;
    },
  },
};
</script>

<style>
.wrap {
  width: 100%;
  display: flex;
  margin: 0.2rem 0 0 0;
  position: relative;
}

/*左侧的导航样式*/
.nav_left {
  width: 21.1875rem;
  overflow: scroll;
}

.nav_left::-webkit-scrollbar {
  display: none;
}

.nav_content {
  white-space: nowrap;
  padding: 0 0.7rem;
}

.nav_content span {
  display: inline-block;
  padding: 0.4rem 0.6rem;
  font-size: 0.875rem;
}

.nav_content .active {
  border-bottom: 2px solid #7f4395;
  color: #7f4395;
}

.nav_left,
.down {
  float: left;
}

/*右侧导航部分*/
.down {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.gray {
  color: gray;
  display: inline-block;
  vertical-align: middle;
}
</style>

作业4_学生信息管理

<template>
  <div id="app">
    <div>
      <span>姓名:</span>
      <input type="text" v-model.trim="user.name" />
    </div>
    <div>
      <span>年龄:</span>
      <input type="number" v-model.number="user.age" />
    </div>
    <div>
      <span>性别:</span>
      <select v-model="user.sex">
        <option value="男">男</option>
        <option value="女">女</option>
      </select>
    </div>
    <div>
      <button @click="addOrEditFn">添加/修改</button>
    </div>
    <div>
      <table
        border="1"
        cellpadding="10"
        cellspacing="0"
        v-show="arr.length > 0"
      >
        <tr>
          <th>序号</th>
          <th>姓名</th>
          <th>年龄</th>
          <th>性别</th>
          <th>操作</th>
        </tr>
        <tr v-for="(obj, index) in arr" :key="index">
          <td>{{ index + 1 }}</td>
          <td>{{ obj.name }}</td>
          <td>{{ obj.age }}</td>
          <td>{{ obj.sex }}</td>
          <td>
            <button @click="delFn(index)">删除</button>
            <button @click="editFn(obj, index)">编辑</button>
          </td>
        </tr>
      </table>
    </div>
  </div>
</template>

<script>
// 需求1: 铺设页面, 准备初始的数据(自己手写数据结构) - 前面是数组索引+1 *作为序号
// 需求2: 当输入框没有值, 要给用户一个提示, 必须都有值才能增加新数据 (数据驱动页面哦)
// 需求3: 添加功能 - 想好数据结构统一对象的key
// 需求4: 点击编辑功能, 把值赋予到输入框上(不要操作dom, 数据驱动页面)
// 需求5: 用户修改后, 点击相同按钮 - 想想怎么判断怎么是添加还是修改的功能 (提示: 准备一个全局变量, 点过编辑按钮可以让它为true) - 实现编辑后更新页面效果
// 需求6: 点击删除, 删除这行数据
export default {
  data() {
    return {
      user: {
        // 表单里绑定对象
        name: "",
        age: 0,
        sex: "",
      },
      editIndex: -1, // 正在编辑的索引默认打开网页是没有的
      arr: [
        // 数据源
        {
          name: "Tom",
          age: 19,
          sex: "男",
        },
        {
          name: "Jone",
          age: 21,
          sex: "女",
        },
      ],
    };
  },
  methods: {
    addOrEditFn() {
      // 添加/修改方法
      if (
        this.user.name.length === 0 ||
        this.user.age === 0 ||
        this.user.sex.length === 0
      ) {
        alert("请输入内容");
        return;
      }

      if (this.editIndex === -1) {
        // 新增
        this.arr.push({ ...this.user });
      } else {
        // 编辑
        this.$set(this.arr, this.editIndex, { ...this.user }); // 修改数组里某个值导致v-for更新
      }

      // 清空输入框
      this.user.name = "";
      this.user.age = 0;
      this.user.sex = "";
    },
    editFn(theObj, index) {
      // 编辑-点击事件
      this.user = { ...theObj }; // 回显
      this.editIndex = index; // 正在编辑的索引
    },
    delFn(index) {
      // 删除方法
      this.arr.splice(index, 1);
    },
  },
};
</script>
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-26 10:04:39  更:2021-09-26 10:06:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 20:04:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码