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             width: 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小案例

 

 

 

 

 

posted @ 2020-04-15 16:13  Noah_Zhang  阅读(629)  评论(0编辑  收藏  举报