组件是Vue实例的重复使用,可以通过使用自定义标签在html中使用Vue实例
组件的创建
全局组件的创建
在全局中通过使用Vue.component()来创建组件,第一个参数传入一个字符串,表示该组件的名称,在html使用该名称作为自定义标签的标签名,第二个参数为一个对象,包括了组件的信息,模板,数据,方法等。
Vue.component("myCom", {
template: '<h3>this is a component</h3>'
})
在html中使用该名称来作为自定义标签的标签名,要注意的是,如果该字符串中使用了驼峰式命名,如上面的myCom,在html中需要将大写字母转为小写字母并在其前加“-”,上面的组件在html这样使用
<my-com></my-com>
在页面中渲染后变为
<h3>this is a component</h3>
组件的模板也可以使用html中的某个结构,下面的组件使用了id为temp的html结构里的内容
<div id="app">
<my-com></my-com>
</div>
<div id="temp">
<h1>this is the template from temp</h1>
</div>
<script>
Vue.component("myCom", {
template: "#temp"
})
</script>
要注意的是,template中只能有一个根元素,如果有两个根元素,那么会报错,如下面的情况,根元素有h3和p,所以最后会报错。
Vue.component("myCom", {
template: '<h3>this is a component</h3><p>i am the second root</p>'
})
使用外部的结构也是一样的,为了防止报错,最好将外部引用的内容使用多一个div包裹,下面要传递的是一个h1标签和一个span标签,使用div包裹后可以顺利传递
<div id="temp">
<div>
<h1>this is the template from temp</h1>
<span>i also come from temp</span>
</div>
</div>
私有组件的创建
私有组件在Vue实例中的components创建,只能在该实例el属性对应的元素中使用
<div id="app">
<app-com></app-com>
</div>
<script>
let vm = new Vue({
el: "#app",
components: {
appCom: {
template: "<h1>this is the template from app</h1>"
}
}
})
</script>
私有组件中也同样可以使用外部的html结构作为模板
<div id="app">
<my-com></my-com>
</div>
<div id="temp">
<h1>this is the template from temp</h1>
</div>
<script>
let vm = new Vue({
el: "#app",
components: {
appCom: {
template: "<h1>this is the template from app</h1>"
}
}
})
</script>
组件中data和methods的使用
data
组件中data的使用和Vue实例中data的使用有所不同,组件中的data为一个返回对象的方法,数据在返回的对象里面。
<div id="app">
<my-com></my-com>
</div>
<script>
Vue.component('myCom', {
template: "<p>this is the template-------and data is :{{msg}}</p>",
data: function() {
return {
msg: "this is the data of component"
}
}
})
let vm = new Vue({
el: "#app"
})
</script>
为什么data为一个返回对象的函数
如果组件的data为一个对象,那么就会导致使用该组件的Vue实例都共享同一个data
下面模仿一下使用data为一个对象的情况,点击按钮看看会发生什么情况
<div id="app">
<my-com></my-com>
<my-com></my-com>
<my-com></my-com>
</div>
<div id="temp" style="display:none">
<div>
<input type="button" value="add" @click="count+=1">
<p>{{count}}</p>
</div>
</div>
<script>
var myData = {
count: 0
}
Vue.component('myCom', {
template: "#temp",
data: function() {
return myData
}
})
let vm = new Vue({
el: "#app"
})
</script>
我们会发现,不管我们点击哪一个按钮,都会导致所有的数字都加1,这就是组件共享一个data的后果,如果使用函数来返回对象就可以使每个组件都对应一个对象
<div id="app">
<my-com></my-com>
<my-com></my-com>
<my-com></my-com>
</div>
<div id="temp" style="display:none">
<div>
<input type="button" value="add" @click="count+=1">
<p>{{count}}</p>
</div>
</div>
<script>
Vue.component('myCom', {
template: "#temp",
data: function() {
return {
count: 0
}
}
})
let vm = new Vue({
el: "#app"
})
</script>
这里点击一个按钮只会影响同一个Vue实例下的count,不会影响其他的count
组件中的methods
组件中方法的使用和Vue实例中方法的使用是相同的
<div id="app">
<app-com>
</my-com>
</div>
<div id="temp" style="display:none">
<input type="button" value="触发方法" @click="fn">
</div>
<script>
let vm = new Vue({
el: "#app",
components: {
appCom: {
template: "#temp",
methods: {
fn() {
console.log('fn');
}
}
}
}
})
</script>
父组件和子组件的传递
父组件向子组件传递值
父组件向子组件传递值需要通过v-bind(缩写为:)来将值绑定给自定义属性以传给子组件,子组件需要在其props数组中写入该自定义属性名(这里自定义属性如果为驼峰式命名,在html中要处理成以-连接的形式),子组件要使用该值时直接使用该自定义属性名
<div id="app">
<my-com :parent-msg="msg"></my-com>
</div>
<script>
let vm = new Vue({
el: "#app",
data: {
msg: "--the value of parent--"
},
components: {
myCom: {
template: "<h1>the msg from parent is {{parentMsg}}</h1>",
// props中的内容都是可读不可写的,在子组件中修改该值会报错
props: ['parentMsg'],
data: function() {
return {
//在父组件中传过来的名字在子组件中不能再次使用同名,否则会报错
// parentMsg: "the value of child"
}
}
}
}
})
</script>
父组件向子组件传递方法
与传递值使用v-bind来绑定相对应,传递方法时使用v-on(缩写为@)来绑定。在子组件中要调用父组件传过来的方法时,需要使用$emit方法来调用方法,其中第一个参数为父组件传过来的方法名,第二个为要传给该方法的参数。
<div id="app">
<!-- 使用@来绑定 -->
<my-com @func="show"></my-com>
</div>
<div id="temp" style="display:none">
<button @click="childFn">触发事件</button>
</div>
<script>
let vm = new Vue({
el: "#app",
methods: {
show(data) {
console.log(`this is the fn from parent ${data}`)
}
},
components: {
myCom: {
template: "#temp",
methods: {
childFn() {
//绑定方法 第二个参数起为方法的参数
this.$emit('func', '子组件中的参数')
}
}
}
}
})
</script>
动态组件
如果在某个位置要实现多个组件的选择使用,就要用到动态组件了,如果只有两个选择时,我们可以使用v-if和v-else来完成动态组件的实现。
<div id="app">
<input type="button" value="first" @click="flag=true">
<input type="button" value="second" @click="flag=false">
<app-com1 v-if="flag"></app-com1>
<app-com2 v-else></app-com2>
</div>
<script>
let vm = new Vue({
el: "#app",
data: {
flag: true
},
components: {
appCom1: {
template: "<p>this is the first template</p>"
},
appCom2: {
template: "<p>this is the second template</p>"
}
}
})
</script>
但是如果是三个甚至以上的选择组件的话,这么实现就不太现实了,这个时候我们可以使用Vue的<component>元素和v-bind绑定的is属性来实现动态组件
在data中使用一个属性来存储要选择的组件名,is属性对应的值则为要使用的组件的名称,通过改变存储的组件名就可以实现动态组件
<div id="app">
<button @click="name='first'">first</button>
<button @click="name='second'">second</button>
<button @click="name='third'">third</button>
<component :is="name"></component>
</div>
<script src="lib/vue.js"></script>
<script>
Vue.component("first", {
template: "<h1>this is the first template</h1>"
})
Vue.component("second", {
template: "<h1>this is the second template</h1>"
})
Vue.component("third", {
template: "<h1>this is the third template</h1>"
})
let vm = new Vue({
el: "#app",
data: {
name: "first"
}
})
</script>
Vue实例中操作DOM和组件
Vue实例中操作DOM
Vue中建议不直接操作DOM,但是如果需求中需要我们对DOM进行操作或者获取DOM元素的内容,我们可以使用ref属性来实现。使用了ref属性的元素,其DOM对象会储存在其所在的Vue实例中的$refs对象中,通过ref属性对应的值来调用该对象。
<div id="app">
<input type="button" @click="getEl" value="按钮">
<h1 ref="myh1">i am the msg in h1</h1>
</div>
<script>
let vm = new Vue({
el: "#app",
methods: {
getEl() {
// this.$refs.myh1是一个DOM对象
console.log(this.$refs.myh1.innerHTML)
}
}
})
</script>
Vue实例中操作组件
Vue实例中操作组件与操作DOM类似,都要用到ref属性,通过这种方式,可以在父组件中调用子组件中的方法,下面的代码中,在按下父组件按钮时,同时会触发子组件的方法。
<div id="app">
<input type="button" @click="getEl" value="父组件按钮">
<h1 ref="myh1">i am the msg in h1</h1>
<login ref="childTemp"></login>
</div>
<div id="temp" style="display:none">
<input type="button" @click="show" value="子组件按钮">
</div>
<script>
let vm = new Vue({
el: "#app",
methods: {
getEl() {
// this.$refs.myh1是一个DOM对象
console.log(this.$refs.myh1.innerHTML)
//调用子组件的方法
this.$refs.childTemp.show()
}
},
components: {
login: {
template: "#temp",
methods: {
show() {
console.log('here is the child template')
}
}
}
}
})
</script>