zoukankan      html  css  js  c++  java
  • vue使用过滤器filter报错:[Vue warn]: Error in render: "TypeError: Cannot read property '0' of undefined"

    背景
    今天在做一个小案例,将数据填在表格里。但是表格里价格一栏的数据要随数量变化。
    问题
    这里我用filter过滤器做。直接报错:
    [Vue warn]: Error in render: "TypeError: Cannot read property '0' of undefined"
    而且页面也没内容了。
    注释掉过滤器就正常显示,所以我认为是我的过滤器有问题。
     1 <tbody>
     2     <tr v-for="(b,index) in books" :key="index">
     3         <td>{{b.id}}</td>
     4         <td>{{b.name}}</td>
     5         <td>{{b.time}}</td>
     6         <td>{{b.price | priceReal(index) | priceFormat}}</td>
     7         <!-- <td>{{b.price | priceFormat}}</td> 这个没问题 -->
     8         <td>
     9             <button class="btn" @click="decrease(index)">-</button>
    10             {{b.counter}}
    11             <button class="btn" @click="increase(index)">+</button>
    12         </td>
    13         <td><button>删除</button></td>
    14     </tr>
    15 </tbody>
    1 filters: {
    2 priceReal(val1, index) {
    3     return val1 * this.books[index].counter; //报错
    4 },
    5 priceFormat(val2) {
    6     return '¥' + val2.toFixed(2);
    7 },
    8 }
    解决问题
    从报错信息看,应该是这个index为0时没有对象。所以我们先打印一下index以及this.books看看
    1 priceReal(val1, index) {
    2     console.log(val1,index);
    3     console.log(this);
    4     console.log(this.books);
    5     // return val1 * this.books[index].counter;
    6 },
    打印结果如下:
    这里形参传过来值是没问题,但是下面到books数组就出问题了。关键问题出在this上,我们想调用的是vue的实例对象下的books数组,这个this却是window,说明我没拿到books,难怪会说第一个数组内容就未定义!
     
    现在只要调用vue实例对象就可以了。
    首先设置全局变量
     1 let that; 
    再在vue实例的“创建对象之前” 钩子函数里给that赋值:
    1 beforeCreate() {
    2     that = this;
    3 },

    过滤函数里打印that

    1 priceReal(val1, index) {
    2     console.log(val1,index);
    3     console.log(this);
    4     console.log(that);
    5     console.log(this.books);
    6     // return val1 * this.books[index].counter;
    7 },
    结果
     
    现在终于可以用了。
     
    ps:不过,最后我还是没用filter做这个功能,因为filter改变的数据不是响应式的。即使filter改了数值,在用computed计算属性时也不会发生变化。
     
    总结
    1、过滤器调用data里的数据时,this指向的是window而不是vue实例。这个需要注意!
    2、filter过滤器不适合做需要响应式的数据。它更适合做格式上的变化。比如大写转小写,数字连接字符串,对一串字符进行筛选等等。
     
    源码
      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <meta charset="UTF-8">
      5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
      6     <title>基本模板语法案例</title>
      7     <style>
      8         * {
      9             padding: 0;
     10             margin: 0;
     11         }
     12         #app {
     13             margin: 200px auto;
     14             width: 600px; 
     15         }
     16         table {
     17             border-collapse: collapse;
     18             border: 1px solid #cccccc;
     19             text-align: center;
     20             width: 600px;
     21         }
     22         th {
     23             background-color: #999;
     24             color: #ffffff;
     25         }
     26         th, td {
     27             border: 1px solid #cccccc;
     28         }
     29         .btn {
     30             width: 20px;
     31         }
     32         /* tbody td:nth-child(5) button {
     33              20px;
     34         } */
     35     </style>
     36 </head>
     37 <body>
     38     <div id="app">
     39         <table>
     40             <thead>
     41                 <tr>
     42                     <th></th>
     43                     <th>书籍名称</th>
     44                     <th>出版日期</th>
     45                     <th>价格</th>
     46                     <th>购买数量</th>
     47                     <th>操作</th>
     48                 </tr>
     49             </thead>
     50             <tbody>
     51                 <tr v-for="(b,index) in books" :key="index">
     52                     <td>{{b.id}}</td>
     53                     <td>{{b.name}}</td>
     54                     <td>{{b.time}}</td>
     55                     <td>{{b.price | priceFormat}}</td>
     56                     <td>
     57                         <button class="btn" @click="decrease(index)">-</button>
     58                         {{b.counter}}
     59                         <button class="btn" @click="increase(index)">+</button>
     60                     </td>
     61                     <td><button @click="del(index)">删除</button></td>
     62                 </tr>
     63             </tbody>
     64         </table>
     65         <div>
     66             <p>总价:{{totalPrice | priceFormat}}</p>
     67             <p>总数量:{{totalCounter}}</p>
     68             
     69         </div>
     70     </div>
     71     <script src="../js/vue.js"></script>
     72     <script>
     73         let that; //设置vue对象为全局变量
     74         const app = new Vue({
     75             el: '#app',
     76             data: {
     77                 books: [{ //图书数据
     78                     id: 1,
     79                     name: '《水浒传》',
     80                     time: '2020-4-15',
     81                     price: 85,
     82                     counter: 1
     83                 }, {
     84                     id: 2,
     85                     name: '《红楼梦》',
     86                     time: '2020-4-15',
     87                     price: 98,
     88                     counter: 1
     89                 }, {
     90                     id: 3,
     91                     name: '《三国演义》',
     92                     time: '2020-4-15',
     93                     price: 10,
     94                     counter: 1
     95                 }, {
     96                     id: 4,
     97                     name: '《西游记》',
     98                     time: '2020-4-15',
     99                     price: 49,
    100                     counter: 1
    101                 }],
    102                 // totalPrice: 0,
    103             },
    104             methods: {
    105                 increase(index) { //增加数量
    106                     const price = this.books[index].price/this.books[index].counter;//books里的price变量不是单价,而是该书的小计,所以这里要先把单价保存起来,后面使用。
    107                     this.books[index].counter++;
    108                     this.books[index].price = price * this.books[index].counter;
    109                 },
    110                 decrease(index) { //减少数量
    111                     const price = this.books[index].price/this.books[index].counter;
    112                     this.books[index].counter--;
    113                     this.books[index].price = price * this.books[index].counter;
    114                     if (this.books[index].counter <= 0) { //数量小于等于0去掉这本书 
    115                         this.del(index);
    116                         // this.$options.methods.del(this);这个方法报错
    117                     }
    118                 },
    119                 del(index) { //删除该书
    120                     this.books.splice(index, 1);
    121                 }
    122             },
    123             computed: {
    124                 totalPrice() { //总价格
    125                     let p = 0;
    126                     for (let b of this.books) {
    127                         p += b.price;  
    128                     }
    129                     return p;
    130                 },
    131                 totalCounter() { //总数量
    132                     let c = 0;
    133                     for (let b of this.books) {
    134                         c += b.counter;
    135                     }
    136                     return c;
    137                 }
    138             },
    139             beforeCreate() { //创建之前保存vue实例对象
    140                 that = this;
    141             },
    142             filters: {
    143                 // priceReal(val1, index) {
    144                 //     return val1 * that.books[index].counter; //如果要调用data里的变量,好像过滤器不方便
    145                 // },
    146                 priceFormat(val2) { //将整型数据格式化
    147                     return '' + val2.toFixed(2);
    148                 },
    149             }
    150         });
    151     </script>
    152 </body>
    153 </html>
    更多vue小案例

  • 相关阅读:
    读《人人都是产品经理》
    前端值得看的博客
    git 常用命令 创建查看删除分支,创建查看删除tag等
    看《如何令选择变得更加容易》
    读【失控】——众愚成智
    html5 postMessage
    下拉滚动加载更多数据
    html select用法总结
    分布式系统事务一致性解决方案
    nginx简易教程
  • 原文地址:https://www.cnblogs.com/Gensokyo/p/12706075.html
Copyright © 2011-2022 走看看