1. 组件
1.1 全局组件
全局组件,全局任何 Vue
实例都可以使用,在 Vue
实例创建之前创建。
1. 方式一
<body>
<div id="app">
<!-- 使用 -->
<mycom1></mycom1>
<!-- <my-Com1></my-Com1> -->
</div>
<script src="./lib/vue-2.4.0.js"></script>
<script>
// Vue.extend 创建全局组件
var com1 = Vue.extend({
template: '<h3>全局组件</h3>'
})
// Vue.component('组件名称', 创建出来的组件模块对象)
// 若组件名称使用驼峰名,那么使用组件名时中间必须有横线 -
// Vue.component('myCom1', com1)
Vue.component('mycom1', com1)
var vm = new Vue({
el: '#app',
data: {},
methods: {}
})
</script>
</body>
简写,省略为一步:
Vue.component('mycom1', Vue.extend({
template: '<h3>全局组件</h3>'
}))
2. 方式二
- 可以省略
Vue.extend
- 将组件模板直接定义在
template
元素中,然后定义id
属性,最后在组件中取id
属性即可
<body>
<div id="app">
<mycom2></mycom2>
<mycom3></mycom3>
</div>
<!-- template 必须 Vue 实例之外 -->
<template id="com3">
<h2>在 template 中定义模板</h2>
</template>
<script src="./lib/vue-2.4.0.js"></script>
<script>
Vue.component('mycom2', {
template: '<h3>全局组件创建方式二</h3>'
})
Vue.component('mycom3', {
template: '#com3'
})
var vm = new Vue({
el: '#app',
data: {},
methods: {}
})
</script>
</body>
Tips:template 必须 Vue 实例之外,模板中有且只能有一个根元素,不能有多个根元素
<!-- 不能存在多个根元素 -->
<template id="com3">
<h2>在 template 中定义模板</h2>
<h3>哈哈</h3>
</template>
<!-- 只能有一个根元素 -->
<template id="com3">
<div>
<h2>在 template 中定义模板</h2>
<h3>哈哈</h3>
</div>
</template>
1.2 局部组件
局部组件,Vue
实例中定义的组件,仅能 Vue
实例使用。
<body>
<div id="app">
<mycom4></mycom4>
</div>
<template id="com4">
<h2>局部组件</h2>
</template>
<script src="./lib/vue-2.4.0.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {},
components: {
// 组件名称
mycom4: {
template: '#com4'
}
}
})
</script>
</body>
1.3 组件 data 和 method
- 组件
data
必须是一个方法 data
内部必须返回一个对象- 使用方式与实例中
data
一致 method
:与实例中一样
<body>
<div id="app">
<mycom4></mycom4>
</div>
<template id="com4">
<div>
<h2>局部组件:{{ msg }}</h2>
<input type="button" value="按钮" @click="btn">
<p v-if="flag">{{ msg }}</p>
</div>
</template>
<script src="./lib/vue-2.4.0.js"></script>
<script>
// 组件 data 必须是一个方法
// data 内部必须返回一个对象才行
// 使用方式与实例中 data 一致
Vue.component('mycom4', {
template: '#com4',
data: function () {
return {
msg: '组件 data',
flag: false
}
},
methods: {
btn() {
this.flag = true
}
}
})
var vm = new Vue({
el: '#app',
data: {},
methods: {},
})
</script>
</body>
1.4 组件切换
在同一元素区域通过点击不同按钮,来显示不同元素,就可以使用组件切换来实现,比较常见的有:登陆注册
- 点击登陆按钮,切换到登录框
- 点击注册按钮,切换到注册框
1.4.1 使用 flag 标识符结合 v-if 和 v-else 切换组件
<body>
<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 src="./lib/vue-2.4.0.js"></script>
<script>
// 登陆组件
Vue.component('login', {
template: '<h3>登陆组件</h3>'
})
// 注册组件
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
var vm = new Vue({
el: '#app',
data: {
flag: false
},
methods: {},
})
</script>
</body>
缺点
flag
标识符只有两种状态,true
和 false
,即最多只能切换两个组件
1.4.2 使用 :is 属性来切换不同的子组件
Vue
提供 :is
属性来解决组件之间的切换,它没有组件数量的限制。
<body>
<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>
</div>
<script src="./lib/vue-2.4.0.js"></script>
<script>
// 登陆组件
Vue.component('login', {
template: '<h3>登陆组件</h3>'
})
// 注册组件
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
var vm = new Vue({
el: '#app',
data: {
comName: 'login' // 当前 component 中的 :is 绑定的组件的名称
},
methods: {},
})
</script>
</body>
默认 comName
为 login
,即为登陆组件,等点击注册按钮时,comName
赋值为 register
,即可切换到注册组件。
1.4.3 组件切换动画
1、使用 transition
元素包裹 component
,mode
属性设置组件切换时候的模式:
<div id="app">
<a href="" @click.prevent="comName='login'">登陆</a>
<a href="" @click.prevent="comName='register'">注册</a>
<!-- 通过 mode 属性,设置组件切换时候的模式,先出后进,这样就不会有前一个组件还未消失,后一个组件就切换进入 -->
<transition mode="out-in">
<component :is="comName"></component>
</transition>
</div>
2、设置切换样式:
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(150px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
</style>
参考文章:
1.5 父子组件间传值
1.5.1 父组件向子组件传值
在子组件中不能直接使用父组件的 data
上的数据 和 methods
中的方法,需要通过 props
传递,两个步骤:
1、使用 v-bind
或简化指令,将数据传递到子组件中:
<div id="app">
<!-- 给子组件绑定一个属性 parentmsg,值为 msg,即父组件的 data -->
<com1 v-bind:parentmsg="msg"></com1>
</div>
2、使用 props
属性来定义父组件传递过来的数据:
<script src="./lib/vue-2.4.0.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: "父组件"
},
methods: {
},
components: {
// data 上的数据,都是可读可写的;
data() {
return {
title: 123
}
}
com1: {
template: '<h3>子组件 :{{ parentmsg }}</h3>', // 在子组件中使用
props: ["parentmsg"] // 在 porps 中定义该属性, props 中的数据,都是只读的,无法重新赋值
},
}
})
</script>
1.5.2 父组件方法传递给子组件
如何将父组件 method
传递给子组件:
1、父组件将方法的引用(字符串形式),传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时将要传递给父组件的数据,在调用方式时
当做参数传递进去。
<div id="app">
<!-- 父组件向组组件传递 method,使用事件绑定机制 v-on,当自定义一个事件属性后,子组件中就能够通过某些方式 -->
<!-- 来调用传递进来的这个方法 -->
<com @func="show"></com>
</div>
<template id="tmp1">
<div>
<h1>子组件</h1>
<input type="button" value="点击触发父组件传递过来的 func 方法" @click="myclick">
</div>
</template>
2、子组件内部通过 this.$emit('方法名', 参数)
方法,来调用父组件中的方法,同时将数据传递给父组件:
<script src="./lib/vue-2.4.0.js"></script>
<script>
// 定义一个字面量的全局子组件
var com = {
template: '#tmp1', // 指定 ID,加载 template 元素中内容
data() {
return {
somMsg: { 'name': 'rose'}
}
},
methods: {
myclick() {
// 子组件中通过 this.emit('父组件事件属性', 参数一,参数二...),即可调用父组件中传递过来的方法
this.$emit('func', this.somMsg)
}
}
}
var vm = new Vue({
el: '#app',
data: {
datamsgFromdson: null
},
methods: {
show(data) {
console.log(data)
this.datamsgFromdson = data
}
},
components: {
com // 注册子组件
}
})
</script>
1.5.3 评论列表示例
练习:父子之间 data
和 method
传递。
1、html
<div id="app">
<com @func="add"></com>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<ul class="list-group">
<li class="list-group-item" v-for="item in list" :key="item.id">
<span class="badge">评论人:{{ item.user }}</span>
{{ item.content }}
</li>
</ul>
</div>
</div>
</div>
<!-- 子组件模板 -->
<template id="tmp1">
<div class="row" style="margin-top: 5%;">
<div class="col-md-8 col-md-offset-2">
<div class="form-group">
<label for="">评论人:</label>
<input type="text" class="form-control" v-model="user">
</div>
<div class="form-group">
<label for="">评论内容:</label>
<input type="text" class="form-control" v-model="content">
</div>
<div class="form-group">
<input type="button" class="btn btn-primary" value="发表评论" @click="postComment">
</div>
</div>
</div>
</template>
2、js
<script src="./lib/vue-2.4.0.js"></script>
<script>
var com = {
template: '#tmp1',
data() {
return {
user: '',
content: '',
}
},
methods: {
// 发表评论
postComment() {
// this.$emit('func', this.user, this.content)
// this.user = this.content = ''
// 存入 localStorage
// 1、组织一个评论数据对象
// 2、localStorage 仅支持字符串,JSON.stringify() 转换为字符串
// 3、保存最新的评论之前,从 localStorage 中获取之前的评论,转换为数组,再将最新的评论 unshift 到这个数组
// 4、若获取的评论为空,不存在,则返回一个 [],JSON.parse 转换不会报错
// 5、再将评论数组转换为字符串,setItem 存入到 localStorage 中
var comment = { id: new Date(), user: this.user, content: this.content }
// 从 localStorage 中获取评论数组(取出时为字符串),并转换为数组
var list = JSON.parse(localStorage.getItem('cmts') || '[]')
list.unshift(comment)
// 重新保存
localStorage.setItem('cmts', JSON.stringify(list))
this.user = this.content = '' // 清空输入框
// 调用父组件方法
this.$emit('func')
}
}
}
var vm = new Vue({
el: '#app',
data: {
list: [
{ id: Date.now(), user: '李白', content: '天生我材必有用' },
{ id: Date.now(), user: '江小白', content: '劝君更尽一杯酒' },
{ id: Date.now(), user: '小马', content: '我姓马, 风吹草低见牛羊的马' }
]
},
created() {
this.add()
},
methods: {
// add(name, comment) {
// this.list.unshift({ id: Date.now(), user: name, content: comment})
// }
add() {
// 从 localStorage 中取出评论数据
var list = JSON.parse(localStorage.getItem('cmts') || '[]')
this.list = list
}
},
components: {
com
}
})
</script>
将新评论存储到 localStorage
中,父组件 add
方法再从 localStorage
中获取所有评论列表,并将其渲染到页面中,
在 created
生命周期函数中调用 add
方法,以保证刷新时最新评论不会消失。
2.6 ref 获取 DOM 元素和组件
使用 this.$refs
来获取元素对象和组件(数据、方法),this.$refs
获取的是 DOM
元素对象,因此可以通过其获取元素的文本、属性等。
<div id="app">
<input type="button" value="获取元素" @click="getElement">
<h3 ref="myh3">标题三</h3>
<com ref="son"></com>
</div>
<template id="tmp1">
<h1>子组件,标题一</h1>
</template>
<script src="./lib/vue-2.4.0.js"></script>
<script>
var com = {
template: '#tmp1',
data() {
return {
msg: "som msg"
}
},
methods: {
show() {
console.log('子组件方法')
}
}
}
var vm = new Vue({
el: '#app',
data: {},
methods: {
getElement() {
// 获取 h3 的文本值
// console.log(this.$refs.myh3.innerText)
// 获取子组件的 data 数据
// console.log(this.$refs.son.msg)
// 执行子组件的 show 方法
this.$refs.son.show()
}
},
components: {
com
}
})
</script>
Tips:在浏览器中 F12 -- console 中,vm.$refs 可查看页面中的 refs 对象,refs 也可以用来替代父子组件直接传值