1、根实例问题
vue中的根实例可以有多个,每个根实例可以挂载DOM元素,只有在挂载的DOM元素上才可以使用该实例中的数据方法等。
并且,组件只有在某一个根实例所挂载的DOM元素上才可以使用。
2、组件的data选项
一个组件的 data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。组件中的data
写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data。如果data值为对象,将导致多个实例共享一个对象,其中一个组件改变data属性值,其它实例也会受到影响。
3、vue-cli初始运行项目报错
安装vue-cli:直接npm i vue-cli -g,然后直接vue init webpack projectname,然后进入目录,npm run dev即可,如果报错:Module build failed: Error: "extract-text-webpack-plugin" loader is used without the corresponding plugin, refer to https://github.com/webpack/extract-text-webpack-plugin for the usage example,解决方法如下:
在 webpack.dev.conf.js
中添加 extract-text-webpack-plugin
配置如下
const ExtractTextPlugin = require('extract-text-webpack-plugin') ........ plugins: [ ............. // extract css into its own file new ExtractTextPlugin({ filename: utils.assetsPath('css/[name].[contenthash].css'), // set the following option to `true` if you want to extract CSS from // codesplit chunks into this main css file as well. // This will result in *all* of your app's CSS being loaded upfront. allChunks: false, }), ]
参照:https://my.oschina.net/dkvirus/blog/1583258
4、命名问题
4.1、自定义事件命名
vue 中的自定义事件在被触发时(子组件触发父组件的自定义事件),驼峰法和横线法不会进行自动转换即不会自动匹配,所以事件名需要完全一致。并且在DOM中的事件名都会被转换为小写,所以如果你在 JS 代码中如果使用了驼峰法,而 DOM 中也使用了驼峰法,则会匹配不上而报错。
所以事件命名推荐使用横线连接符(kebab-case)而不是驼峰命名法(camelCase )。
4.2、prop的命名
在DOM中即父组件使用中使用横线连接符(kebab-case)命名,在子组件中可以使用横线或者驼峰法,都能匹配上。
推荐使用横线连接符命名
4.3、组件的命名
组件的命名可以使用分隔线或者首字母大写的驼峰法。
当使用分隔线命名时(比如:my-component-name),使用组件的时候也得使用分隔线;
当使用首字母大写的驼峰法时(比如:MyComponentName),在使用组件时可以使用分隔线也可以使用首字母大写驼峰法。但是当直接在 DOM 中使用时,此时应该使用分隔线,因为在 HTML 中不区分大小写,所以在HTML中使用驼峰法可能会因为匹配不上而报错。
推荐使用横线连接符命名
5、 语法糖
语法糖是指用另一种语法替换原先的比较复杂的语法,但实现的功能一样,这种比较简单清晰的语法被称为语法糖。
vue 中的语法糖有:
- v-bind 的语法糖是:":"
- v-on 的语法糖是:"@"
- v-model 也是一个语法糖,v-model = "test" 的实际写法可以写成 :value = "test" @input = " test = $event.target.value "
- v-slot 的语法糖是:"#",该缩写只有在有参数时才能用,比如具名插槽:<template #header> </template>
6、组件中的 name 属性的作用
组件中是有 name 属性的,组件的 name 属性主要有以下几个作用:
6.1、允许组件递归地引用本身
在自身组件调用自身的时候,可以通过定义name的值进行递归调用
<div> <div v-for="(item,index) of list" :key="index"> <detail-list></detail-list> </div> </div> export default { name: 'DetailList', //组件可以利用 name 属性递归地调用本身 props: { list: [1,2,3] } }
6.2、使用 keep-alive 缓存组件
<!-- 失活的组件将会被缓存!--> // 下面的 is 后面的名字应该是组件的 name 属性值 <keep-alive> <component v-bind:is="currentTabComponent"></component> </keep-alive>
组件在全局用 Vue.component()
注册时,全局 ID 自动作为组件的 name。
<keep-alive>
要求被切换到的组件都有自己的名字,不论是通过组件的 name
选项还是局部/全局注册。
6.3、报错警告信息明确,使用 vue-devtools 开发更易于调试
指定 name 选项的另一个好处是便于调试,有名字的组件有更友好的警告信息。
另外,当在有 vue-devtools,未命名组件将显示成 <AnonymousComponent>
,这很没有语义。如果组件有 name 属性,那在 vue-devtools 中显示的将是 name 的值,组件树更有语义。
7、Vue 中的字符串模板和DOM模板
Vue 中的字符串模板指的应该是包括在引号 ' ' 或者双引号 " " 之间的,包括在这之间时可以使用一切 JS 表达式,而不用拘泥于大小写问题。
而 DOM 模板就是非字符串模板,指的是在 HTML 内的,而且没有在引号之间。
8、关于父子组件props传值的响应式修改问题
父子组件之间可以通过 props 进行传值,在父组件中修改传过去的值时,在子组件中接收到的 props 值都会随之发生改变。但是如果把 props 的值赋值给 data 中的数据时,data 中的数据不一定会随之改变。
当 props 值不是对象时,直接赋值给 data 属性,data 属性不会发生响应式改变。比如当 props 值是对象时,如果直接赋值给 data 属性,data 属性会发生响应式改变,如果将对象的某个属性或者直接将某个基本类型值赋值给 data 属性,此时子组件中该 data 属性不会发生响应式改变。
总而言之,将对象赋值给 data 属性会随之发生改变,将基本类型值赋值给 data 属性则不会发生响应式改变。
//父组件 parent.vue <button @click="editName">点击修改数据</button> <item01 :name-prop="name" :human-prop="human" /> data() { return { name: 'wen', human: {name: '人类'} } }, methods: { editName () { //点击修改传过去的 props 值 this.name = 'hai' this.human.name = '动物' } } //子组件 child.vue props: ['nameProp','humanProp'], //props值会响应式地发生改变 data() { return { myName: this.nameProp, //不是对象的值直接赋值给 data 属性,此时不会发生响应式改变 myHuman: this.humanProp //对象直接赋值给 data 属性,会发生响应式改变 myHumanName: this.humanProp.name //对象属性赋值给 data 属性,也不会发生响应式改变 } } {{nameProp}} -- {{humanProp}} //props值 都会响应式地发生改变 {{myName}} //data属性 此时不会改变 {{myHuman.name}} //这里会改变 {{myHumanName}} //这里不会改变
请注意:是子组件中的 data 属性的数据不会发生响应式改变,但 props 属性的值都是会响应式改变的。所以如果你不需要修改传过来的值的话,你也可以直接用 props 属性的值,而不用赋值给 data 中的属性值。
8.1、如何解决子组件接收的基本值类型的数据时不会发生响应式改变的问题
上面说到如果将值类型的 props 值赋值给 data 属性时,data 属性不会随着父组件的数据的改变而发生改变,要想解决这个问题,可以通过监听 props 的值,当 props 的某个值发生改变时,再将其赋值给 data 属性。
//子组件 child.vue {{myName}} //此时会发生响应式改变 props: ['name','human'], //props值会响应式地发生改变 data() { return { myName: this.name, //不是对象的值直接赋值给 data 属性,此时不会发生响应式改变 } }, watch: { name (newVal, oldVal) { //通过监听将新的props值赋值给data属性 this.myName = newVal; //或者: this.myName = this.name } }
当然,如果不需要修改传递过来的值时,你也可以直接使用接收的 prop 的值进行操作,而无需赋值给组件的 data,这样就不用监听改变了。