文章目录
1.Vue组件名推荐使用大驼峰命名法
为什么我们一直在强调 Vue
组件命名使用大驼峰呢???
在此之前,我们对 Vue
组件已经有啦一定的了解,我们也知道局部组件的使用频率会高于全局组件,推荐使用大驼峰命名也和我们局部组件的使用有关,接下来我们慢慢分析.
我们先写一个简单的组件来观察一下:
<div id="app">
<!-- 在注册了局部组件的实例中使用局部组件 -->
<my-component></my-component>
</div>
<script>
// 1.创建剧组件选项对象
let MyComponent = ({
template:`
<div>
<h3>我是组件1</h3>
</div>
`
})
let vm = new Vue({
el:"#app",
//2. 将选项对象注册为局部组价
components:{
"my-component":MyComponent,
}
})
</script>
在上面的代码中:
- 首先定义了一个选项对象
mycomponent
, - 在
Vue
的实例化对象中将该实例化对象定义为了一个局部组件 - 在html模板中通过标签
<my-component></my-component>
使用局部组件
在上面的例子中,我们并没有使用驼峰命名法,但是组件一件可以正常使用.
那么我们看下面的两点:
- 定义选项对象的时候使用的变量名不能包含连字符,这是标识符的命名规则,毫无疑问,如果我们非要在定义选项对象的时候使用连字符,那么就必须加引号;
- 在上面的代码中,我们在
Vue
的实例化对象中注册组件的时候,componnets
选项中是一个对象,my-component
时我们后面要使用的组件名称,MyComponent
就是我们要注册为组件的选项对象.
如果我们的选项对象和组件名相同会发生什么事呢,在es6中我们知道,如果对象中的属性名和属性值相同的时候,我们就可以简写,想下面这样:
const vm = new Vue({
el:"#app",
components: {
//普通写法
MyComponent: MyComponent
//es6的写法
MyComponent
}
})
所以有没有发现我们为什么要腿甲使用驼峰命名法,从这里就可以看出来了吧.
当我们定义组件的选项对象的时候使用驼峰命名,就是说和需要被注册为组件的选项对象和组件名字一致的时候,注册组件将会变得很简单.
但是我们通常不会只注册一个组件,当我们需要注册多个组件的时候,就可以按照下面这种写法:
let vm = new Vue({
el:"#app",
//2. 将选项对象注册为局部组价
components:{
first,second,three
}
})
怎么样,代码有没有变得比以前优雅很多.
总结:
1. 定义组件时最好使用驼峰命名
2. 注册组件的时候,最好让组件名和即将被注册为组件的选项对象名称一致
3. 在 html 总使用组件的时候使用连字符
2.template选项
虽然有语法糖简化了组建的注册,但是在 template
选项中拼接 HTML
元素依旧比较麻烦,这也导致了 html
和 JavaScript
的耦合性太高.
Vue.js提供了两种方法将定义在 JavaScript
中的 html
分离出来.
2.1 使用 Script 标签分离
使用 script
标签分离 JavaScript
内的 html
的内容,此时 script
标签内会有一个 id
属性,通过这个 id
关联.
<div id="app">
<my-component></my-component>
</div>
<script id="myCom" type="text/x-template">
<div>
<h3>我是组件1</h3>
</div>
</script>
<script>
let MyComponent = ({
template:"#myCom"
})
let vm = new Vue({
el:"#app",
components:{
MyComponent,
}
})
尽管我们可以使用 script
标签将 html
的内容分离出来,但是要注意在 script
标签内的 type
值的选择.
使用这种方式后,此时的 template
已经不再是一个 html
模板了.而是一个 id
值,Vue.js
根据这个 id
查找对应的元素,然后将这个元素内的 HTML
作为模板进行编译。
注意的点:
使用<script>
标签时,type指定为text/x-template,意在告诉浏览器这不是一段js脚本,浏览器在解析HTML文档时会忽略<script>
标签内定义的内容。
2.2 使用 template 标签分离
如果我们选择使用 template
标签来分离模板,那么就只需要指定 id
的值,不再需要 type
属性.
示例代码如下:
<div id="app">
<my-component></my-component>
</div>
<template id = "MyCom">
<div>
<h3>我是组件1</h3>
</div>
</template>
<script >
let MyComponent = ({
template:"#MyCom"
})
let vm = new Vue({
el:"#app",
components:{
MyComponent,
}
})
</script>
在我们已经了解了组件基本使用之后,选择使用 script
标签或者是 template
标签来分离内容这种方式会更好一些,折让我们的 html
代码和 JavaScript
代码之间是相互分离的,更有利于我们的维护.
3. 组件选项中的特例
组件中的选项基本与实例选项对象一致, 但是有两个选项是特例,分别为el 和 data 属性.
这两个选项在在选项对象和实例对象中的使用方式是不同的.
3.1 组件选项中没有el
el
属性在实例对象中的作用我们是了解的,他用来绑定我们的 Vue
实例将来要接管的 DOM
元素,而我们的组件是在实例中使用的,所以并不需要指定 el
.
如果我们强行为它绑定 el
则会报错.所以要记住的是组件的选项对象中没有 el
属性.
3.2 组件中的data属性为什么是一个函数???
组件中的data选项必须是一个函数,返回一个数据对象
他为什么不是和vue的实例化选项中一样是一个函数呢?我们看下面的内容
3.2.1 组件中的data是对象的情况
不能使用对象的原因:
- 组件中会被重复多次调用
- 而对象是引用数据类型,如果组件数据使用对象的话,那么组件所有的复用都共享这些数据.
看下面的代码:
<div id="app">
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
<template id = "MyCom">
<div>
<h3>我是组件{{num}}</h3>
<button @click="add">点击数字会增加哦</button>
</div>
</template>
<script >
//在这种情况下点击一下,所有的数组都会增加,这不符合我们的目的,我们希望的结果是这些数据之间是不要互相干扰的
let data = {
num:1,
}
let MyComponent = ({
template:"#MyCom",
//在组件的data中直接写对象是会报错的,所以我们通过data函数中return出的对象来模拟data的值为对象的情况
data:function () {
return data;
},
methods:{
add() {
this.num++
}
}
})
let vm = new Vue({
el:"#app",
components:{
MyComponent,
}
})
当我点击其中的任何一个按钮时,每一个的数字都会增加,原因是这三个组件共用了一个数据对象,所以当数据对象中的数据一旦发生改变,那么所有使用了这个数据的地方都会跟着改变.
一些说明的点:
- 如果直接在选项对象的
data
中定义一个对象就会报错 - 因此我们使用
return
将data
中的对象提取出来,以这样的方式让所有的组件共用一个数据对象
通过案例我们就会发现如果所有的组件都共享数据,当有一个组件中的数据发生了变化,所有的组件显示的数据都会发生变化, 这不是我们想要的.我们想要的是每个数据之间不会相互影响.
3.2.2 组件中的data是函数的情况
所以组件的 data
数据属性才会需要函数,每次初始化化的时候都会执行函数,将返回的结果作为组件的数据,
这样每次执行函数都会给每个组件创建一个独立的数据
实例代码如下:
<div id="app">
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
<template id = "MyCom">
<div>
<h3>我是组件{{num}}</h3>
<button @click="add">点击数字会增加哦</button>
</div>
</template>
<script >
// data是个函数,每次执行都会返回新的数据
//当其中某一个组件的数据发生改变的时候并不会影响其他的组件
let MyComponent = ({
template:"#MyCom",
data() {
//函数每次执行都会返回一个新的数据,这个数据并不是共享数据
return {
num : 1
}
},
methods : {
add() {
this.num++
}
}
})
let vm = new Vue({
el:"#app",
components:{
MyComponent,
}
})
当我点击按钮的时候,只会有自己的数据发生变化,其他的组的数据并不会发生变化,这是因为虽然我们对组件进行了复用,但是每次复用的组件都有自己的数据对象,因此在数据上并不会相互影响.
一个组件数据发生改变的时候, 其他组件的数据不会变化,因为每个组件都有自己独立的数据.
4.组件的使用问题
通过上面上的例子我们已经了解了组件的使用,就是把组件名当做自定义标签使用,但是这种使用方法有的时候也会出现问题.
看下面的内容就会了解:
4.1 组件标签解析错误
示例代码如下:
<div id="app">
<table>
<my-component></my-component>
</table>
</div>
<template id = "MyCom">
<tr>
<td>内容</td>
<td>123</td>
</tr>
</template>
<script>
let MyComponent =({
template:"#MyCom",
})
let vm = new Vue({
el:"#app",
components:{
MyComponent,
}
})
</script>
虽然按照我们的想法实现了,但是有没有发现, tr
标签竟然在 table
标签的外面,
我们使用这个组件的目的就是希望在 table
标签中渲染 tr
标签,结果他跑去外面了…
原因在与浏览器规范中 table
标签里面必须放 tr
标签,但是我们放的是 my-component
自定义标签,所以在解析的时候就会出问题.
当使用 DOM
作为模板时 (例如,使用 el
选项来把 Vue
实例挂载到一个已有内容的元素上),你会受到 HTML
本身的一些限制,因为 Vue
只有在浏览器解析、规范化模板之后才能获取其内容。
尤其要注意,像<ul>
、<ol>
、<table>
、<select>
这样的元素里允许包含的元素有限制,而另一些像 <option>
这样的元素只能出现在某些特定元素的内部。通俗一点讲,就是“龙生龙,凤生凤,老鼠的儿子会打洞.
特殊的一下父元素如<ul>
、<ol>
、<table>
、<select>
里面不能包含不属于它的子元素,而与之相对应的<li>
、<tr>
、<option>
只可以出现在特定的父元素里面。
4.2 通过is属性使用组件
vue允许我们使用 is
属性来使用组件, is
属性的值是组件名
所以可以采用 is
属性来制定组件
<div id="app">
<table>
<tr is="my-component"></tr>
<tr is="my-component"/>
<tr is="my-component"/>
</table>
</div>
<template id = "MyCom">
<tr>
<td>姓名</td>
<td>学号</td>
<td>性别</td>
</tr>
</template>
<script>
let MyComponent =({
template:"#MyCom",
})
let vm = new Vue({
el:"#app",
components:{
MyComponent,
}
})
</script>
此时我们就会发现不仅结果没问题, 编译后标签的嵌套也没有什么问题,
因为我们是按照标准在 tbody
标签中使用的是 tr
标签,只不过通过 is
属性将tr标签替换为了组件 my-component
的模板标签.
此时 tr
标签中没有嵌套内容,所有使用单标签,双标签都可以