Vue基础(Bug集)

106 阅读9分钟

1. JS语法类错误

1.1. 报错:xx is not defined

错误描述: 变量未定义

  • 有问题代码:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app"></div>
<script>
  const vm = new Vue({
    el: '#app',
    methods: {
      add() {
        // 使用了未申明的变量a
        a++
      }
    },
    mounted() {
      this.add()
    }
  })
</script>
  • 报错图示:

1.png

  • 分析:

vue框架针对这类错误会给出俩块错误提示

标记为1的地方是vue框架给出的发生错误的组件中的位置 上图的意思是错误发生在Root根组件的mounted声明周期函数中

标记为2的地方是vue框架给出的发生错误的js语言中调用栈的位置 上图的意思是错误发生在add方法调用的时候

  • 解决:

!> 这一类错误都是相同的排错方式 按照下面的步骤即可

  1. 根据1错误块得到错误发生在哪个组件以及具体发生在组件的哪个阶段
  2. 根据2错误块找到错误发生的调用栈位置 直接点击定位错误
  3. 根据错误信息提示在错误定位的地方修改即可

2. Vue框架规则类错误

2.1. 报错: Vue is not defined

错误提示: Vue没定义啊

  • 有问题代码:
<body>
  <div id="app"></div>
</body>
<script>
  new Vue({
    el:'#app'
  })
</script>
  • 报错图示:

    报错4

  • 分析

Vue全局变量哪里来的啊? 是不是引入vue.js才暴露在全局的啊, 就跟$变量也是引入jQuery.js才有的

所以证明你没有引入Vue.js
  • 解决:
去引入vue.js源码到你的页面中即可

2.2. 问题: 不解析内容

错误描述: 运行后, 出现了双大括号, 不解析了

  • 报错提示

报错2

  • 分析:
1. 先看看浏览器是否有报错 有报错提示根据提示解决问题
2. 可能把标签内容都写在了<div id="app"> </div> 外面去了
  • 解决

把内容都写到div#app里面来, 因为vue指定了以#app为根标签, 按照你写的模板结构, vue会创建一套虚拟DOM解析真正的内容和标签, 然后替换到这个标签上来, 写外面你让vue咋解析?

2.3. 报错: Do not mount Vue to

错误描述: 不能使用html或body作为vue的模板根标签

  • 有问题代码:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--错误!挂载到根元素-->
<body id="app"></body>
<script>
    new Vue({
    el:'#app'
  })
</script>
  • 报错图示:

01.png

  • 分析
Vue框架不允许把html或者body作为挂载的根元素
  • 解决:

把挂载根元素换成普通元素即可

<div id="app"></div>

2.4. 报错: Property or method 'xxx' is not defined on the instance

错误描述: 属性或方法没定义

02.png

  • 有问题代码:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
  <!--模板使用了name但是在实例选项中没有申明-->
  {{name}}
</div>

<script>
  const vm = new Vue({
    el: '#app',
    computed:{}
    data: {},
    methods: {}
  })
</script>
  • 分析

在vue组件实例的模板中使用到的属性值或者方法必须要在实例的配置项中定义好才可以使用

  • 解决

根据错误提示的内容,去组件实例选项中查看是否未定义该属性,查找范围包括data,computed,methods,props

在data: {} 里面定义name变量

2.5. 报错: the data property 'name' is already defined

错误描述: xxx already defined 就是已经定义过了的提示, 肯定重复定义了变量名哦

  • 有问题代码:
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            name: 'cp'
        },
        props: {
            name: {
                type: String
            }
        },
        computed: {
            name() {}
        },
        methods: {
            name() {
                console.log(`cp`)
            }
        }
    })
</script>
  • 报错图示:

03.png

  • 分析

Vue框架不允许data/props/computed/methods中任意两项出现重复的属性名,在初始化配置时会进行名称检测

  • 解决

根据错误提示找到哪里发生了重复,找到重复属性名更改为不重复即可

2.6. 报错: Duplicate keys detected

错误描述: 发现重复的key

  • 有问题代码
<script src="./vue.js"></script>

<div id="app">
  <ul>
    <li v-for="item in list" :key="item.id">
      {{item.name}}
    </li>
  </ul>
</div>

<script>
  const vm = new Vue({
    el: '#app',
    data: {
      // 这里有重复id
      list: [
        { id: 1, name: 'react' },
        { id: 2, name: 'vue' },
        { id: 1, name: 'angular' }
      ]
    }
  })
</script>
  • 报错图示:

1.png

  • 分析

为保证列表的高效更新 vue框架在我们使用v-for指令的时候要求为每一项绑定一个唯一的key属性,注意key必须是唯一不可重复的 代码中的存在重复的id 所以会报错

  • 解决

每次给key绑定值时确保是唯一的值

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
  <ul>
    <li v-for="item in list" :key="item.id">
      {{item.name}}
    </li>
  </ul>
</div>

<script>
  const vm = new Vue({
    el: '#app',
    data: {
      // 这里有重复id
      list: [
        { id: 1, name: 'react' },
        { id: 2, name: 'vue' },
        { id: 3, name: 'angular' }
      ]
    }
  })
</script>

2.7. 报错: the data option should be a function

错误描述: 说你的data选项必须是一个方法

  • 有问题代码:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app"></div>

<script>
Vue.component('add-component', {
    // 错误!!
    data: {
        name: 'cp'
    }
})
const vm = new Vue({
    el: '#app'
})
</script>
  • 报错图示:

04.png

  • 分析

上面申明的组件add-component上面的data属性直接配置了一个对象,这在vue的组件系统中是不允许的,因为组件的核心使用场景是复用,data如果直接赋值一个对象,那么多个重复的组件会共用一套数据,一个组件进行数据更改所有组件都会受到影响,违背了组件的功能独立性

  • 解决:

任何一个组件的data都应该申明为一个函数,函数中返回一个对象,这个全新的对象作为组件的依赖数据

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app"></div>

<script>
Vue.component('add-component', {
    // 正确
    data(){
        return {
            name:'cp'
        }
    }
})
const vm = new Vue({
    el: '#app'
})
</script>

2.8. 报错: Component template should contain exactly one root element

错误描述: 组件模板应该只包含一个根元素标签

  • 有问题代码:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
    <add-component></add-component>
</div>

<script>
    Vue.component('add-component', {
        template: `
<div></div>
<p></p>
`
    })

    new Vue({
        el: '#app'
    })
</script>
  • 报错图示:

image.png

  • 分析:

    vue组件的的template选项中只能拥有一个根元素 原因是因为一是为了做组件样式隔离,二是为了渲染时存放当前的组件对应的vnode,所以只能有一个根元素 这在vue3.0中会得到改善

  • 解决:

只写一个根元素

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
    <add-component></add-component>
</div>

<script>
    Vue.component('add-component', {
        template: `
<div></div>
`
    })

    new Vue({
        el: '#app'
    })
</script>

2.9. 报错: do not use build-in or reserved HTML elements as

错误描述: 不能将内置或保留的html元素用作组件

  • 有问题代码
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app"></div>

<script>
  // 错误!!
  Vue.component('header', {
    data(){
      return {}
    }
  })
  const vm = new Vue({
    el: '#app'
  })
</script>
  • 报错图示:

05.png

  • 分析

Vue框架对于组件的命名规则有一定限制,不允许和HTML内置标签发生名称重复,上面组件的名称header和HTML内置标签中的header标签重复,关于vue中的组件命名希望大家严格遵守

  • 解决

将组件名称替换成规范的命名规则即可

2.10. 报错: Unknown custom element

错误描述: 不知道自定义的标签, 你注册了吗?

  • 有问题代码
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
    <father-component></father-component>
</div>

<script>
    Vue.component('father-component', {
        template:`
<div>
我是父组件
<son-component></son-component>
    </div>
`
    })
    const vm = new Vue({
        el: '#app',
        components:{
            'son-component':{
                template:`
<div>我是子组件</div>
`
            }
        }
    })
</script>
  • 报错图示:

image.png

  • 分析

    组件 并没有在父组件 中注册,所以并不能正常使用,大家一定要记着,全局组件在每一个vue实例的模板中都能正常使用,而局部注册的组件只有在父组件的components选项中注册时候才能使用

  • 解决

在父组件的components中注册一下组件即可

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
  <father-component></father-component>
</div>

<script>
  Vue.component('father-component', {
    template:`
      <div>
        我是父组件
        <son-component></son-component>
      </div>
    `,
    // 注册局部组件!!!
    components:{
      'son-component':{
        template:`
          <div>我是子组件</div>
        `
      }
    }
  })
  const vm = new Vue({
    el: '#app'
  })
</script>
  • 总结: 谁用谁注册哦~全局的不用注册, 直接用

2.11. 报错: Failed to mount component: template or render function not defined

错误描述: 无法装载组件:未定义模板或呈现函数

  • 有问题代码:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
    <add-component></add-component>
</div>

<script>
    Vue.component('add-component', {
        data() {
            return {}
        }
    })
    new Vue({
        el: '#app'
    })
</script>
  • 报错图示:

8.png

  • 分析

    尝试渲染组件,但是组件中既没有tempalte选项又没有render函数,因为vue组件的渲染最终是要执行render函数的,如果render函数存在就以render函数为准,如果render函数不存在,则会把template选项编译成为render函数再执行 所以这俩个需要申明其中的一个

  • 解决

申明template选项或者申明render函数

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  Vue.component('add-component', {
    template:`
     <div>this is add-component</div>
    `,
    data() {
      return {}
    }
  })
  new Vue({
    el: '#app'
  })
</script>

2.12. 报错: Avoid mutating a prop directly since the value will be overwritten

错误描述: 避免直接改变属性,因为值将被覆盖

  • 有问题代码
<script src="./vue.js"></script>
<div id="app">
    <add-component title="this is title"></add-component>
</div>
<script>
        Vue.component('add-component', {
        props: {
            title: {
                type: String
            }
        },
        template: `
<div>
{{title}}
<button @click="change">修改数据</button>
</div>
`,
        methods:{
            change(){
                // 尝试直接修改父组件传过来的数据
                this.title = 'new title'
            }
        }
    })
new Vue({
    el: '#app'
})
</script>
  • 报错图示:

9.png

  • 分析:

    上面的代码中,title数据来源于父组件,在子组件按钮点击时尝试直接修改title数据,基于vue单向数据流的要求,我们不能反向子组件直接修改父组件的数据 所以会报错

  • 解决:

可以通过事件传递的方式,通过调用父组件的一个方法进行修改title数据,这样的话就符合父组件修改自己数据的要求,或者我们可以把props中的title赋值给子组件data中的一个新的值,让它成为子组件自己的数据,这样的话就可以子组件自己修改了

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
  <add-component title="this is title"></add-component>
</div>

<script>
  Vue.component('add-component', {
    props: {
      title: {
        type: String
      }
    },
    data() {
      return {
        childTitle: this.title
      }
    },
    template: `
     <div>
      {{childTitle}}
      <button @click="change">修改数据</button>
     </div>
    `,
    methods: {
      change() {
        this.childTitle = 'new title'
      }
    }
  })

  new Vue({
    el: '#app'
  })
</script>

2.13. 报错: Computed property "xxx" was assigned to but it has no setter

错误描述: 计算属性想被赋值, 但是它没有setter方法

  • 有问题代码
<div id="app">
<input type="checkbox" v-model="isAll">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    new Vue({
    el: "#app",
    computed: {
        isAll(){
            return true;
        }
    }
})
</script>
  • 报错图示:

    计算属性需要set和get

  • 分析:

    发现v-model会把标签的value值/状态值绑定给v-model指定的变量, 而变量又是给计算属性, 计算属性默认只返回值, 不是给它赋值

  • 解决:

    修改computed里的代码即可, 给计算属性一个set的机会, 但是千万不要在这里给计算 属性赋值, 会引起递归的

computed: {
    isAll: {
        set(val) { // 设置isAll的值的时候触发此方法, 传入要设置的值
            // val是全选框的true/false的值
            this.arr.map(obj => {
                obj['checked'] = val;
            })
        },
        get() {
            return this.arr.every(obj => obj['checked'] == true);
        }
    }
}

2.14. 报错: avoid using JavaScript unary operator as property name

错误描述: 避免使用JavaScript一元运算符作为属性名

  • 有问题代码
<tr v-for="(obj, index) in list">
    <td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.time }}</td>
<td>
    <button @click="delete(index)">删除</button>
</td>
</tr>
  • 报错图示:

    image-20210119200954791

  • 分析:

报错的意思是说你使用了一元运算符作为属性名, 而且报错里一直说delete有问题

后来百度一查发现delete是个关键字

所以以后不要用delete作为变量名/方法名哦
  • 解决:

    把delete换个名字使用和定义即可

<tr v-for="(obj, index) in list">
    <td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.time }}</td>
<td>
    <button @click="delBtn(index)">删除</button>
</td>
</tr>


methods: {
    delBtn(index){
        // 2. 给删除按钮绑定点击事件 - 传递过来对应绑定的index索引值
        // 删除数组里对应的元素, vue会自动更新页面
        this.list.splice(index, 1);
    }
}

2.15. 报错: Templates should only be responseible for mapping the state to the UI

错误描述: 模板应该只负责将状态映射到UI

  • 有问题代码
<body>
    <div id="app">
        <ul>
            <li v-for="item in arr">{{item}}</li>
        </ul>

        <!-- 2. 引入 vue.js-->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script>
            // 3. 实例化vue对象 (把视图配置进来让vue解析)
            new Vue({
                el: "#app", // 指向视图的名字(选择器/dom标签)
                data: { // vue世界用到的变量
                    arr: ["春天", "夏天", "秋天", "冬天"] // 变量名叫arr, 值是一个数组4个元素
                }
            })

        // 哇哦, 真香
        </script>
    </div>
</body>

</html>
  • 报错图示:

    image-20210121230017265

  • 分析:

报错说只负责把状态更新到UI, 而且下面波浪线画的是script标签, 说明你script不是模板代码啊

Vue会把#app指定标签内的代码认为是模板代码, 怎么把script也认为了? 

看代码结构, 发现把script写#app标签里了我的天啊...
  • 解决: 把script标签等拿出来啊

3. 拼写类错误

3.1. 报错: Error in mounted hook: "TypeError: xxx is not a function"

错误描述: xxx不是一个方法

  • 有问题代码:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
</div>
<script>
  const vm = new Vue({
    el: '#app',
    data: {
      name: "cp"
    },
    // 拼写类错误
    method:{
      add(){}
    },
    mounted(){
      this.add()
    }
  })
</script>
  • 报错图示:

4.png

  • 分析

!> 此类错误并不会直接告诉你是拼写错了,如果你发现貌似根据错误提示怎么找都找不到,那么试着检查下,vue的配置项是不是拼写错了

  • 解决: methods 配置项

4. 其他错误

4.1. 报错: this dependency was not found

错误描述: 找不到此依赖项

  • 有问题代码:
import "@api/hmmm/questions"
  • 报错图示:

image-20210228221103394

  • 分析

说找不到@api/hmmm/questions模块, 但是这是我们自己建立的, 为啥让我们下载, 应该是路径写错了导致未找到

  • 解决:

@代表的是src文件夹, 你想访问src文件夹下的api文件夹, 正确写法 @/api

import "@/api/hmmm/questions"

4.2. 报错: Invalild options in vue.config.js

错误描述: 在vue配置文件中非法的选项

  • 报错图示:

image.png

  • 分析

    看报错提示红色, 在vue.config.js中 devServe不被允许, 知道devServer才是正确的选项对吧?

  • 解决:

    把devServe 改成 devServer即可