组件: 顾名思义, 也就是组成的部件, 即整体的组成部分
这个组成部分是可以缺少的,但是其存在的意义是无可替代的
这个组成部分也是可以复用的
全局方法一:
大致可以分成三步
1.在我们引入vue.js之后,Vue会被注册为一个全局对象,我们使用对象本身的方法进行组件的创建
------使用Vue这个全局对象的component方法进行全局注册一个组件
2.创建根实例,进行视图的绑定
3.组件的显示
-----将组价的名称作为标签写在视图内部,就能够完成组件的显示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--引入js-->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--3. 定义的组件名作为标签存在,将组件显示在页面上-->
<my-component></my-component>
</div>
</body>
</html>
<script>
//1. 使用vue这个全局队形内置的components方法进行组件的创建
//在components这个方法中有两个重要的参数,第一个参数是组件的名称,第二个参数是组件的内容
Vue.component('my-component', {
//在这里使用一个父标签将组件包裹起来
template: '<div><a href="#">注册</a><a href="#">登录</a></div>'
})
//2. 创建根实例,也就是实例化一个vue对象,进行视图的绑定
var vm = new Vue({
el: '#app'
})
</script>
全局方法二
使用全局的Vue.extend()构造器进行注册
Vue.extend()类似于继承,通过这个构造器扩展(继承)之后,相当于Vue对象本身添加了一些这个对象原先没有的东西
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue入门之extend全局方法</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="app"></div>
</body>
</html>
<script>
//通过构造器创建一个组件,相当于在vue这个全局对象本身上添加了一些新的内容,作用相当于构造函数
//----继承自vue,但是比vue本身更强大
var myVue = Vue.extend({
template: '<div>这是通过构造器创建出来的组件</div>'
});
var app = new myVue({
el: '#app'
});
</script>
局部方法一
大致分成两个部分
1.穿件跟实例
2.在跟实例内部定义组件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--引入js-->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--3. 这是我定义的组件 占位标签-->
<my-component></my-component>
</div>
</body>
</html>
<script>
//1. 创建根实例
var vm = new Vue({
el: '#app',
//2. 在根实例内部创建组件
components:{
'my-component':{
template: '<div><a href="#">注册</a><a href="#">登录</a></div>'
}
}
})
</script>
组件注册的其它方式1
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--引入js-->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--这是我定义的组件-->
<my-component></my-component>
</div>
<template id="my-template">
<div>
<a href="#">注册</a>
<a href="#">登录</a>
</div>
</template>
</body>
</html>
<!--
注意组件的模板替换了自定义元素,自定义元素的作用只是作为一个挂载点。
----这可以用实例选项 replace 改变。
-->
<script>
//1. --定义 + 注册 组件构造器
Vue.component('my-component', {
//将template的内容提取到一个标签中,通过id来获取
template: '#my-template'
})
//2. 创建根实例
var vm = new Vue({
el: '#app'
})
</script>
组件注册的其它方式2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--引入js-->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--这是我定义的组件-->
<template>
<div>
<a href="#">注册</a>
<a href="#">登录</a>
</div>
</template>
</div>
</body>
</html>
<!--
自定义的标签只是自定义组件的一个挂载点,自定义组件会将其替换掉
----直接使用自定义的组件将自定义的标签替换
-->
<script>
//2. 创建根实例
var vm = new Vue({
el: '#app'
})
</script>
组件内部的data
组件内部的data属性必须是一个函数
以全局注册的组件为例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--引入js-->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--全局的组件-->
<ab></ab>
<!--局部的组件-->
<my-component></my-component>
</div>
</body>
</html>
<script>
//自定义指令
//Vue.directive('指令名',{})
//定义组件 参数1:组件的名称 参数2: 对象
Vue.component("ab",{
template:
`<ul>
<li>{{name}}</li>
<li>{{age}}</li>
<li>{{sex}}</li>
</ul>`,
//data属性的属性值是一个函数----函数内部返回一个对象
data:function(){
return {
name:"首页",
age:"联系我们",
sex:"新闻"
}
}
})
//2. 创建根实例-----并在根实例下面创建一个局部的组件
var vm = new Vue({
el: '#app',
//局部组件
components:{
'my-component':{
template: `<ul>
<li>{{name}}</li>
<li>{{age}}</li>
<li>{{sex}}</li>
</ul>`,
data:function(){
return {
name:1,
age:2,
sex:3
}
}
}
}
})
</script>
父子组件通信
父组件将数据传递给自组件使用prop 子组件将其内部发生的事情通告给父组件使用emit
复杂的父子组件的props
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--引入js-->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<parent></parent>
</div>
<template id="parent">
<div>
<div>我是父组件</div>
<child :message="message"></child>
</div>
</template>
<template id="child">
<div>
<div>我是子组件</div>
<span>{{message}}</span>
</div>
</template>
</body>
</html>
<script>
var vm = new Vue({
el: '#app',
//我是父组件
components:{'parent':{
template:"#parent",
data:function(){
return {
message:"hello world"
}
},
//我是子组件
components:{'child':{
props:['message'],
template:"#child"
}}
}}
})
</script>
字面量语法 vs 动态语法
使用字面量语法传递数字,有时候会出现问题
单向数据流
数据从父组件传递到子组件,但是不会反过来传递
数据传递-注意事项
在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,
如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
自定义事件
每个 Vue 实例都实现了事件接口(Events interface),即:
使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件
类似于我们注册(vue中是$on)点击事件,通过鼠标点击触发(vue中是emit)
document.onclick = function(event){
console.log(111)
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<style>
#dv1,
#dv2 {
width: 500px;
height: 100px;
}
#dv1 {
border: 1px solid red;
margin: 50px auto;
}
#dv2 {
border: 1px solid green;
margin: 50px auto;
}
</style>
</head>
<body>
<div id="app2">
<component2></component2>
</div>
<div id="app1">
<component1></component1>
</div>
</body>
</html>
<script type="text/javascript">
//1. 创建一个空的公共的vue对象
var bus = new Vue();
//2. 在vm1实例中创建组件1,定义$emit来发送数据
var vm1 = new Vue({
el: '#app1',
components: {
component1: {
template: `<div id="dv1" v-on:click="add">
<div>点击我,触发自定义事件,进行数据的传递</div>
<div>当前的数据是:{{num}}</div>
</div>`,
data: function() {
return {
num: 0
}
},
methods: {
add: function() {
this.num++;
bus.$emit('test', this.num)
}
}
}
}
})
//在vm2实例中创建组件2,定义$on来接收传递的数据
var vm2 = new Vue({
el: '#app2',
components: {
component2: {
template: `<div id="dv2" v-on:click="result">
<div>点击我,进行自定义事件的注册</div>
<div>传递过来的数据是{{getData}}</div>
</div>`,
data: function() {
return {
getData: 0
}
},
methods: {
result: function() {
//this问题
var vm2This = this;
bus.$on('test', function(num) {
vm2This.getData = num;
//事件的解绑问题
bus.$off("test")
})
}
}
}
}
})
</script>
slot
有时候,我们需要对组件进行局部的修改,
vue提供了一种方式来混合父组件的内容与子组件自己的模板
这个过程被称为 内容分发 也就是slot
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue入门之extend全局方法</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--父容器输入标签,会将slot标签替换掉-->
<my-slot>
<h3>这里是父容器写入的</h3>
</my-slot>
<!--父容器绑定数据到子容器的slot,会将slot中的数据替换掉-->
<my-slot>{{ email }}</my-slot>
<!--父容器什么都不传内容-->
<my-slot></my-slot>
</div>
</body>
</html>
<script>
// 反引号:可以定义多行字符串。
var temp = `
<div>
<h1>这里是子组件</h1>
<hr>
<slot>slot标签会被父容器写的额外的内容替换掉,如果父容器没有写入任何东西,此标签将保留!</slot>
</div>
`;
Vue.component('MySlot', { // 如果定义的组件为MySlot,那么用组件的时候:<my-slot></my-slot>
template: temp,
});
// 初始化一个Vue实例
var app = new Vue({
el: '#app',
data: {
email: 'flydragon@gmail.com'
}
});
</script>
具名slot
元素可以用一个特殊的属性 name 来配置如何分发内容。多个 slot 可以有不同的名字。
具名 slot 将匹配内容片段中有对应 slot 特性的元素
仍然可以有一个匿名 slot ,它是默认 slot ,作为找不到匹配的内容片段的备用插槽。如果没有默认的 slot ,这些找不到匹配的内容片段将被抛弃
动态组件
通过使用保留的 元素,动态地绑定到它的 is 特性,我们让多个组件可以使用同一个挂载点,并动态切换
如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--引入js-->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<h3>动态组件</h3>
<!-- 定义三个temp模板,用于切换 -->
<template id="temp-tab01">
<div>this is tab01</div>
</template>
<template id="temp-tab02">
<div>this is tab02</div>
</template>
<template id="temp-tab03">
<div>this is tab03</div>
</template>
<div id="dr01">
<!-- 导航栏 -->
<div class="border cf">
<ul>
<li>
<a href="javascript:void(0);" @click="toggleTabs(tab01Text);">{{tab01Text}}</a>
</li>
<li>
<a href="javascript:void(0);" @click="toggleTabs(tab02Text);">{{tab02Text}}</a>
</li>
<li>
<a href="javascript:void(0);" @click="toggleTabs(tab03Text);">{{tab03Text}}</a>
</li>
</ul>
</div>
<!-- 点击导航后要切换的内容 -->
<div class="border" style="height: 100px;">
<!-- 如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。为此可以添加一个 keep-alive 指令参数 -->
<component :is="currentView" keep-alive></component>
</div>
</div>
</body>
</html>
<script>
//通过使用保留的 <component> 元素,动态地绑定到它的is属性,我们让多个组件可以使用同一个挂载点,并动态切换:
//扩展组件tab01
var tab01 = Vue.extend({
template: "#temp-tab01",
});
//扩展组件tab02
var tab02 = Vue.extend({
template: "#temp-tab02",
});
//扩展组件tab03
var tab03 = Vue.extend({
template: "#temp-tab03",
});
//新建vue实例
var dr01 = new Vue({
el: "#dr01",
data: {
tab01Text: "tab01", //导航栏文本1
tab02Text: "tab02", //导航栏文本2
tab03Text: "tab03", //导航栏文本3
currentView: 'tab01', //默认选中的导航栏
},
//局部注册组件
components: {
tab01: tab01,
tab02: tab02,
tab03: tab03,
},
methods: {
//绑定tab的切换事件
toggleTabs: function(tabText) {
this.currentView = tabText;
}
}
});
</script>