Vue基础教程--组件(七)
1 创建组件
组件注册
// 1.1 使用 Vue.extend 来创建全局的Vue组件
var myComponent = Vue.extend({
template: '<h3>组件的创建,组件的名称使用驼峰命名(myComponent),使用时需要加-(my-component)</h3>'
})
// 1.2 使用 Vue.component('组件的名称', 创建出来的组件模板对象)
Vue.component('myComponent', myComponent)
组件简写
部分简写
// Vue.component 第一个参数:组件的名称,将来在引用组件的时候,就是一个 标签形式 来引入 它的
// 第二个参数: Vue.extend 创建的组件 ,其中 template 就是组件将来要展示的HTML内容
Vue.component('mycomponentfirst', Vue.extend({
template: '<h3>组件第一种简写方式,组件的名称没有使用驼峰命名(mycomponentfirst),直接使用(mycomponentfirst)</h3>'
}))
全部简写
// 注意:不论是哪种方式创建出来的组件,组件的 template 属性指向的模板内容,必须有且只能有唯一的一个根元素
Vue.component('myComponentSecond', {
template: '<div><h3>组件第二种简写方式</h3><span>组件的 template 属性指向的模板内容,必须有且只能有唯一的一个根元素</span></div>'
})
模板组件
<!-- 在 被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构 -->
<template id="mycom3temp">
<div>
<h1>组件的第三种方式</h1>
</div>
</template>
// 注意:不论是哪种方式创建出来的组件,组件的 template 属性指向的模板内容,必须有且只能有唯一的一个根元素
Vue.component('myComponentThird', {
template: '#mycom3temp'
})
局部组件
<template id="privatecom">
<h1>这是私有的组件</h1>
</template>
var vm = new Vue({
el: '#app',
data: {},
methods: {},
components: { // 定义实例内部私有组件的
mycom4: {
template: '#privatecom'
}
}
});
组件的使用
如果要使用组件,直接,把组件的名称,以 HTML 标签的形式,引入到页面中,即可
<div id="app">
<my-component></my-component>
<mycomponentfirst></mycomponentfirst>
<my-component-second></my-component-second>
<mycom3></mycom3>
<mycom4></mycom4>
</div>
效果展示
2 组件数据
data 必须是一个函数
// 1. 组件可以有自己的 data 数据
// 2. 组件的 data 和 实例的 data 有点不一样,实例中的 data 可以为一个对象,但是 组件中的 data 必须是一个方法
// 3. 组件中的 data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行;
// 4. 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!!
Vue.component('mycom1', {
template: '<h1>全局组件 -- {
{msg}}</h1>',
data: function () {
return {
msg: '组件data定义的数据'
}
}
})
组件中的数据为什么必须是个函数呢,假如组件中的数据是公有的,那么在组件的复用时,公有数据会出现混乱现象
<div id="app">
<counter></counter>
<hr>
<counter></counter>
<hr>
<counter></counter>
</div>
<template id="tmpl">
<div>
<input type="button" value="+1" @click="increment">
<h3>{
{count}}</h3>
</div>
</template>
<script>
var dataObj = {
count: 0 }
// 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 +1
Vue.component('counter', {
template: '#tmpl',
data: function () {
return dataObj
},
methods: {
increment() {
this.count++
}
}
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
},
methods: {
}
});
</script>
效果展示
从效果展示可以看出随便动一个组件其他组件的数据也会随之相加。
3 组件切换
3.1 组件切换第一种方式<v-if><v-else>
<div id="app">
<a href="" @click.prevent="flag=true">登录</a>
<a href="" @click.prevent="flag=false">注册</a>
<login v-if="flag"></login>
<register v-else="flag"></register>
</div>
<script>
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
flag: false
},
methods: {
}
});
</script>
3.2 组件切换第二种方式<component>
<div id="app">
<a href="" @click.prevent="comName='login'">登录</a>
<a href="" @click.prevent="comName='register'">注册</a>
<!-- Vue提供了 component ,来展示对应名称的组件 -->
<!-- component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称 -->
<component :is="comName"></component>
<!-- 总结:当前学习了几个 Vue 提供的标签了??? -->
<!-- component, template, transition, transitionGroup -->
</div>
<script>
// 组件名称是 字符串
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
comName: 'login' // 当前 component 中的 :is 绑定的组件的名称
},
methods: {
}
});
</script>
3.3 两种方式的效果展示
4 父子组件之间传值
4.1 父组件向子组件传值
子组件中,默认无法直接访问到父组件中的 data 上的数据和methods 中的方法
<div id="app" align="center">
<!-- 父组件,可以在引用子组件的时候, 通过 属性绑定(v-bind:) 的形式, 把 需要传递给 子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用 -->
父组件 --- {
{msg}}
<com1 v-bind:parentmsg="msg"></com1>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: '父组件中的数据'
},
methods: {
},
components: {
com1: {
template: '<h1 @click="change">子组件 --- {
{ parentmsg }}</h1>',
// 注意: 组件中的 所有 props 中的数据,都是通过 父组件传递给子组件的
// props 中的数据,都是只读的,无法重新赋值(实际可以赋值,但是会拋错)
props: ['parentmsg'], // 把父组件传递过来的 parentmsg 属性,先在 props 数组中,定义一下,这样,才能使用这个数据
directives: {
},
filters: {
},
components: {
},
methods: {
change() {
this.parentmsg = 'msg信息修改'
}
}
}
}
});
</script>
效果展示
从效果展示可以看出子组件可以通过v-bind和props获取父组件信息,但是props中的数据都是只读的,效果展示中可以看出:
- 对props中的数据做出修改只有子组件做出了修改,父组件不会发生变化,
- props中的数据做了修改会有报错提示。所以不建议修改props中的数据
4.1.1 父组件向子组件循环传值
<div id="app" align="center">
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
></blog-post>
</div>
<script>
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{
{ title }}</h3>'
})
var vm = new Vue({
el: '#app',
data: {
posts: [
{
id: 1, title: 'My journey with Vue' },
{
id: 2, title: 'Blogging with Vue' },
{
id: 3, title: 'Why Vue is so fun' }
]
},
methods: {
getElement() {
// ref 是 英文单词 【reference】 值类型 和 引用类型 referenceError
this.parentMsg = this.$refs.mylogin.msg
this.$refs.mylogin.show()
}
}
});
</script>
效果展示
4.2 父组件把方法传递给子组件(子组件向父组件传值)
<div id="app" align="center">
{
{datamsgFormSon}}
<!-- 父组件向子组件 传递 方法,使用的是 事件绑定机制; v-on, 当我们自定义了 一个 事件属性之后,那么,子组件就能够,通过某些方式,来调用 传递进去的 这个 方法了 -->
<com @comfunc="show"></com>
</div>
<template id="tmpl">
<div>
<h1>子组件</h1>
<input type="button" value="这是子组件中的按钮 - 点击它,触发父组件传递过来的方法" @click="myclick">
</div>
</template>
<script>
// 定义了一个字面量类型的 组件模板对象
var com = {
template: '#tmpl', // 通过指定了一个 Id, 表示 说,要去加载 这个指定Id的 template 元素中的内容,当作 组件的HTML结构
data() {
return {
sonmsg: {
name: '小头儿子', age: 6 }
}
},
methods: {
myclick() {
this.$emit('comfunc', this.sonmsg)
}
}
}
var vm = new Vue({
el: '#app',
data: {
datamsgFormSon: null
},
methods: {
show(data) {
this.datamsgFormSon = data
}
},
components: {
com
}
});
</script>
效果展示
从效果展示可以看出子组件通过v-on(简写@)和emit成功绑定了父组件的show方法。并且成功传值给了父组件
4.3 子组件向父组件传值(ref)
<div id="app" align="center">
{
{parentMsg}}<br/>
<input type="button" value="获取元素" @click="getElement" ref="mybtn">
<h3 ref="myh3">ref获取DOM元素</h3>
<hr>
<login ref="mylogin"></login>
</div>
<script>
var login = {
template: '',
data() {
return {
msg: 'son msg'
}
},
methods: {
show() {
alert('调用了子组件的方法')
}
}
}
var vm = new Vue({
el: '#app',
data: {
parentMsg: ''
},
methods: {
getElement() {
// ref 是 英文单词 【reference】 值类型 和 引用类型 referenceError
this.parentMsg = this.$refs.mylogin.msg
this.$refs.mylogin.show()
}
},
components: {
login
}
});
</script>
效果展示
从效果展示可以看出父组件通过ref成功调用了子组件的show方法和获取了子组件的msg信息
4.3 子组件向父组件传值(v-model)
<input v-model="searchText">
等价于:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value">
<div id="app" align="center">
<custom-input v-model="searchText"></custom-input>
</div>
<script>
Vue.component('custom-input', {
props: ['value'],
template: `<input type="text"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)">`
})
var vm = new Vue({
el: '#app',
data: {
searchText: "父组件"
}
});
</script>
效果展示
5 通过插槽分发内容(slot)
<div id="app" align="center">
<alert-box>
Something bad happened.
</alert-box>
</div>
<script>
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
var vm = new Vue({
el: '#app'
});
</script>
效果展示
从效果展示可以看出加入后中间内容可以正确显示。