文章目录
Vue 实战
十二、Vue 中组件(component)
1、组件作用
组件作用:用来减少Vue实例对象中代码量,日后在使用Vue开发过程中,可以根据不同业务功能将页面中划分为不同的多个组件,然后由多个组件去完成整个页面的布局,便于日后使用Vue进行开发时页面管理,方便开发人员维护。
2、组件使用
(1)全局组件祖册
说明:全局组件直接注册给Vue实例,日后可以在任意Vue实例的范围内使用该组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Vue系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--2.使用全局组件,在Vue实例范围内-->
<!--登录-->
<login></login>
<!--注册-->
<register></register>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
// 1.定义一个全局组件,参数1:组件名称 参数2:组件的配置对象
Vue.component(`login`, {
template: `<div><h2>用户登录</h2> <form action=""></form></div>`
});
Vue.component(`register`, {
template: `<div><h2>用户注册</h2> <form action=""></form></div>`
})
var app = new Vue({
el: "#app",
data: {
msg: "Vue中组件之全局组件的使用"
}
})
</script>
注意
Vue.component()
:用来开发全局组件
- 参数1:组件的名称
- 参数2:
组件配置{}对象
template
:··
用来书写组件的 html 代码template
中必须有且只有一个root
元素- 使用时需要在Vue的作用范围内根据组件名称使用全局组件
- 如果在注册组件过程中使用 驼峰命名组件的方式 在使用组件时 必须将驼峰的所有单词小写加入
-
线进行使用- 注意:无论使用全局组件还是局部组件都必须在组件template中加入唯一根元素
(2)局部组件注册(用的最多)
说明:通过将组件注册给对应Vue实例中一个 components
属性来完成组件注册,这种方式不会对Vue实例造成叠加
- 第一种开发方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Vue系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--局部组件使用,在Vue实例作用范围内-->
<!--用户登录-->
<login></login>
<!--用户添加-->
<add></add>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
// 局部组件登录模板声明
let login = { // 具体局部组件名称
template: `<div><h2>用户登录</h2></div>`
}
const app = new Vue({
el: "#app",
data: {
msg: "Vue中组件之局部组件的使用"
},
methods: {},
computed: {},
components: { // 用来注册局部组件
// login: login,
// 简写
login, // 登录局部组件
add: { // 添加局部组件
template: `<div><h2>用户添加</h2> <form action=""></form></div>`
}
}
})
</script>
- 第二种开发方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Vue系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--4.局部组件使用,在Vue实例作用范围内-->
<!--用户登录-->
<login></login>
</div>
<!--1.声明局部组件模板 template 标签 注意:在Vue实例作用范围外声明-->
<template id="loginTemplate">
<h1>用户登录</h1>
</template>
</body>
</html>
<script src="js/vue.js"></script>
<script>
//2.定义变量用来保存模板配置对象
let login = {//具体局部组件名称
template: `#loginTemplate` //使用自定义template标签选择器即可
}
const app = new Vue({
el: "#app",
data: {
msg: "Vue中组件之局部组件的使用"
},
methods: {},
computed: {},
components: { //用来注册局部组件
//login:login,
//简写
login, //3.注册组件
}
})
</script>
(3)Vue组件中定义data、methods、computed、生命周期函数以及子组件
- 代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Vue系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--使用组件: 直接通过组件名-->
<login></login>
<register></register>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
Vue.component('register', {
template: `<div><h3>我是注册</h3><span>{{msg}}</span></div>`,
data() {
return {
msg: "我是注册全局组件中数据"
}
}
});
//登录组件配置对象
const login = {
template: `<div id="aa">
<h2>用户登录</h2>
<h2>{{counter}}---{{msg}}---{{counterSqrt}}---{{counterSqrt}}----{{counterSqrt}}</h2>
<button @click="test(10)">点我counter++</button>
<aa></aa>
<register></register>
</div>`, //用来书写组件html代码
data() { //用来给当前组件定义属于组件自己数据 组件中定义数据 data必须是一个函数
return {
counter: 1,
msg: "我是组件msg"
}
},
methods: { //用来给组件自己定义一系列方法
test(count) {
this.counter += count;
}
},
computed: { //用来给组件自己定义一些列计算方法
counterSqrt() {
return this.counter * this.counter;
}
},
//初始化阶段
beforeCreate() {
console.log("beforeCreate:", this.msg);
},
created() {//在这个函数执行时Vue实例对象已经存在自身内部事件和生命周期函数以及自定义data methods computed
console.log("created:", this.msg);
},
beforeMount() { //此时组件中template还是模板还没有渲染
console.log(this);
//console.log("beforeMount:",this.$el.innerHTML);
},
mounted() { // 此时组件中页面的数据已经和data中数据一致
console.log("mounted:", document.getElementById("aa").innerHTML);
},
//运行阶段
beforeUpdate() {// 此时data中数据变化了 页面数据还是原始数据
console.log("beforeUpdate:", this.counter);
console.log("beforeUpdate:", document.getElementById("aa").innerHTML);
},
updated() { //此时data 页面数据一致
console.log("updated:", this.counter);
console.log("updated:", document.getElementById("aa").innerHTML);
},
//销毁阶段
beforeDestroy() {
},
destroyed() {
},
components: {
aa: { //定义组件
template: '<div><span>我是aa子组件</span></div>'
},
}
};
const app = new Vue({
el: "#app",
data: {
msg: "Vue的组件中定义组件data、methods、computed、生命周期函数以及子组件"
},
methods: {},
computed: {},
components: { //用来定义局部组件
login,
}
})
</script>
3、Prop的使用
定义:Vue中提供的一个特有的数据传递机制,props
用来给组件传递相应静态数据或动态数据的
作用:在使用Vue组件时如果需要通过父组件给子组件传递数据可以通过 props
进行实现
(1)Vue组件的数据传递之props(通过在组件上声明静态数据传递给组件内部)
- 代码示例一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--使用局部组件-->
<!--3.通过组件完成数据传递-->
<login username="小朱" age="21"></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
//1.声明组件模板配置对象
const login = {
template: `<div><h2>欢迎:{{username}} 年龄:{{age}}</h2></div>`,
props: ["username", "age"], //props作用 用来接收使用组件时通过组件标签传递的数据
}
const app = new Vue({
el: "#app",
data: {
msg: "组件之间数据传递:通过在组件上声明静态数据传递给组件内部"
},
methods: {},
computed: {},
components: {//注册组件
login,//2.注册局部组件
}
})
</script>
- 代码示例二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--使用组件
props 传递静态数据: 就是写死一个数据 动态数据:数据可变得
父组件向子组件传递数据:
a.传递静态数据 在组件使用的标签上 声明静态数据 key=value
b.在组件定义的内部使用props进行接收数据才可以
-->
<!--用户登录-->
<login title="我是标题" count="0"></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
//定义组件对象
const login = {
template: `<div><h3>用户登录----{{title}}---{{loginTitle}}---{{count}}</h3></div>`,
data() {
return {
// title:"我是子组件内部标题", //报错 因为已经props机制内已经有title了 相当于data中已经有了
// count:0,
loginTitle: this.title,
}
},
props: ['title', 'count'],//用来接收父组件给当前组件传递数据 注意:props机制接收数据就相当于自己组件data中声明一个这样数据
};
const app = new Vue({
el: "#app",
data: {
msg: "组件之间数据传递:父组件向子组件传递静态数据"
},
components: { //注册局部组件
login, //注册局部组件login
}
});
</script>
总结
- 在使用组件时可以在组件上定义多个属性以及对应数据
- 在组件内部可以使用
props
数组声明多个定义在组件上的属性名 日后可以在组件中通过{{属性名}}
方式获取数组中属性值
(2)Vue组件的数据传递之props(通过在组件上声明动态数据传递给组件内部)
- 代码示例一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--3.使用局部组件-->
<!--使用 v-bind 形式将数据绑定到Vue实例中data属性中 日后data属性发生变化 组件内部数据跟着变化-->
<login :name="username" :age="age"></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
//1.声明组件模板对象
const login = {
template: `<div><h2>欢迎:{{name}} 年龄:{{age}}</h2></div>`,
props: ["name", "age"],//用来接收父组件给当前组件传递数据 注意:props机制接收数据就相当于自己组件data中声明一个这样数据
}
const app = new Vue({
el: "#app",
data: {
msg: "组件之间数据传递:通过在组件上声明动态数据传递给组件内部",
username: "小朱11",
age: 21,
},
methods: {},
computed: {},
components: {//注册组件
login,//2.注册局部组件
}
})
</script>
- 代码示例二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--
向子组件中传递动态数据 使用props机制:即可以传递静态数据也可以传递动态数据
传递静态数据:组件标签上声明 key=value 组件内部使用props数组进行声明 对应接收key
传递动态数据:组件标签上声明 :key="value" 组件内部使用props数组进行声明 对应接收key
-->
<!--双向绑定-->
<input type="text" v-model="name">
<input type="text" v-model="msg">
<!--使用局部组件-->
<login :name="name" :msg="msg"></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
//定义组件配置对象
const login = {
template: `<div><h2>用户登录--{{name}}--{{msg}}</h2></div>`,
props: ['name', 'msg'],
}
const app = new Vue({
el: "#app",
data: {
msg: "组件间数据传递:父组件向子组件传递动态数据",
name: "我是vue实例管理数据",
},
methods: {},
computed: {},
components: {//注册局部组件
login,
}
})
</script>
(3)Vue组件的数据传递之props(父组件向子组件传递动态数据之单向数据流)
单向数据流:所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
所有的 prop 都使得其父子prop之间形成了一个单向下行绑定:父级prop 更新会向下流动到子组件中,但是反过来则不行 这样会防止从子组件意外改变父级组件的状态 从而导致你的应用的数据流难以理解
额外的,每次父级组件发生更新时,子组件中所有的prop都将会刷新为最新的值,这意味着你不应该在一个子组件内部改变prop。如果你这样做了,Vue会在浏览器的控制台中发出警告。
- 代码示例如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。
如果你这样做了,Vue 会在浏览器的控制台中发出警告
-->
<input type="text" v-model="counter">
<!--使用局部组件-->
<login :count="counter"></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
//声明组件配置对象
const login = {
template: `<div><h3>用户登录--{{aaaCount}}</h3><button @click="incrmentCount">点我改变接收count</button></div>`,
data() {
return {
aaaCount: this.count
}
},
props: ['count'],
methods: {
incrmentCount() {
console.log(this.count);
this.aaaCount++;
}
}
};
const app = new Vue({
el: "#app",
data: {
msg: "组件间数据传递",
counter: 1,
},
methods: {},
computed: {},
components: {//注册局部组件
login,
},
})
</script>
4、组件中定义数据和事件使用
(1)组件中定义属于组件的数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--使用局部组件-->
<login></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
//组件声明的配置对象
const login = {
template: `<div><h2>{{msg}} 百度一下,你就知道</h2><ul><li v-for="item,index in lists">{{index+1}}. {{item}}</li></ul></div>`,
data() {//使用data函数方式定义组件的数据 在templatehtml代码中通过插值表达式直接获取
return {
msg: "hello",
lists: ["java", "python", "c++", "ios"],//组件自己内部数据
}
}
}
const app = new Vue({
el: "#app",
data: {
msg: "组件之间数据传递",
},
methods: {},
computed: {},
components: {//注册组件
login,//注册局部组件
}
})
</script>
(2)组件中事件定义
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--使用局部组件-->
<login></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
//组件声明的配置对象
const login = {
template: `<div><input type="button" value="点我触发组件中事件" @click="change"></div>`,
data() {
return {
name: "小朱",
}
},
methods: {
change() {
alert(this.name);
alert("事件触发");
}
}
}
const app = new Vue({
el: "#app",
data: {
msg: "组件之间数据传递",
},
methods: {},
computed: {},
components: {//注册组件
login,//注册局部组件
}
})
</script>
总结
- 组件中定义事件和直接在Vue中定义事件基本一致,直接在组件内部对应的html代码上加入
@事件名=函数名
即可- 在组件内部使用
methods
属性用来定义对应的事件函数即可,事件函数中this
指向的是当前组件的实例。
5、Vue中父组件向子组件中传递事件并在子组件中调用该事件
在子组件中调用传递过来的相关事件必须使用 this.$emit('函数名')
方式调用
- 代码示例一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<!--3.使用子组件-->
<!--在组件内部使用 this.$emit('find')-->
<login @find="findAll" :name="name"></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
//1.声明组件
const login = {
template: "<div><h1>百度一下 {{ uname }}</h1> <input type='button' value='点我' @click='change'></div>",
data() {
return {
uname: this.name
}
},
props: ['name'],
methods: {
change() {
//调用vue实例中函数
this.$emit('find'); //调用组件传递过来的其他函数时需要使用 this.$emit('函数名调用')
}
}
}
//2.注册组件
const app = new Vue({
el: "#app",
data: {
name: "小朱"
},
methods: {
findAll() { //一个事件函数 将这个函数传递给子组件
alert('Vue 实例中定义函数');
}
},
components: {
login,//组件的注册
}
});
</script>
- 代码示例二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}} {{count}}</h1>
<!--
使用组件
在使用组件时向组件传递事件 直接在对应组件标签上定义传递事件即可 @key=value @传递的事件名="父组件中传递的事件名"
-->
<!--使用局部组件-->
<!--
1.静态数据:name="小朱
2.动态数据::msg="msg"
3.事件传递:@testParent="testParent"
-->
<login name="小朱" :msg="msg" @testParent="testParent" @bb="testHehe"></login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
const login = {
template: `<div><h2>用户登录 --{{name}} --{{msg}}</h2><input type="button" @click="testChild" value="点我去调用父组件中某个事件"></div>`,
props: ['name', 'msg'],
data() {
return {
count: 19,
}
},
methods:{
testChild(){
alert('我是子组件中定义事件');
//调用父组件中testParent事件
this.$emit('testparent');//这个方法用来调用父组件传递过来事件 参数1:调用事件名 注意大小写 testparent
// this.$emit('bb',this.count,'xiaochen',true);//传递零散参数
this.$emit('bb',{count:this.count,name:"小李",sex:true});//传递对象
}
}
}
const app = new Vue({
el: "#app",
data: {
msg: "组件间事件传递",
count: 0,
},
computed: {},
methods: {
testParent() {
alert("我是父组件上定义事件")
},
testHehe(obj){
console.log("parent:","hehe");
console.log("parent:",obj);
console.log("parent:",obj.count);
console.log("parent:",obj.name);
console.log("parent:",obj.sex);
this.count = obj.count;
}
},
components: {//注册局部组件
login,
},
})
</script>
6、Vue组件中的插槽 slot
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}} {{count}}</h1>
<!--
插槽: slot 作用: 用来扩展现有组件 让组件变得更加灵活 usb 接口
具名插槽: 带有名字插槽
默认插槽:
-->
<login></login>
<hr>
<login><span slot="bb">欢迎进入我们网站</span></login>
<hr>
<login><span slot="aa">welcome to website!!! {{msg}}</span></login>
<hr>
<login>
<button slot="aa" @click="incrmentCount()">点我</button>
</login>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
const login = {
template: `<div><slot name="aa"><span>我是默认插槽</span></slot><h3>用户登录</h3><slot name="bb"></slot></div>`
};
const app = new Vue({
el: "#app",
data: {
msg: "组件的slot(插槽)",
count: 0,
},
methods: {
incrmentCount() {
this.count++;
}
},
components: { //注册局部组件
login,
}
});
</script>
7、es6基本语法及使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue之系列课程</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--
ES6: EcmaScript 6.x ====> javascript chrome jscript ie =====> ECMAScript 到今天js依然存在浏览器
EcmaScript: 1.x=====> 7.x 8.x ES11.x
EcmaScript: 5.x 通用版5.x
EcmaScript: 6.x 简称 ES6
1.ES6中变量声明
-->
</div>
</body>
</html>
<script src="js/axios.min.js"></script>
<script src="js/vue.js"></script>
<script>
//es6 1.变量声明 var 原因:使用var声明变量存在作用范围混淆问题
// let :用来声明局部变量 好处:作用范围严谨 从代码声明处开始 到代码块结束 一般在声明基本变量时使用 推荐使用let
// const :用来声明js中常量 好处:一旦被赋值不能被修改 推荐使用这两个关键字声明变量 声明js中对象时推荐使用const
//es6 2.在使用匿名函数时作为参数时候 function(){} 推荐使用es6中箭头函数 (参数,参数)=>{函数体}
/*
axios.get("url").then(function (res) {
}).catch(function (err) {
});
*/
/*
axios.get("url").then((res) => {
}).catch((err) => {
})
*/
//注意:
//1.当箭头函数没雨参数时或者参数大于1个,必须加入()
//2.当箭头函数只有一个参数时 () 可以省略不写
//3.当函数体中只有一行代码时 函数体 {} 可以省略不写
//4.箭头函数和匿名函数的最大区别: 箭头函数没雨自己的this 匿名函数存在自己的this
//es6 3.模板字符串 使用语法:
let html = "<button οnclick=\"test('+id+')\">点我</button>" +
"<button οnclick=\"test('+id+')\">点我</button>" +
"<button οnclick=\"test('+id+')\">点我</button>" +
"<button οnclick=\"test('+id+')\">点我</button>" +
"<button οnclick=\"test('+id+')\">点我</button>" +
"<button οnclick=\"test('+id+')\">点我</button>";
let html1 = `<div>
<h1>我是小黑</h1>
<button οnclick="test()">点我</button>
</div>`;
console.log(html)
console.log(html1)
//es6 对象定义 便利:在定义对象时如果对象属性名和变量名一致,写一个即可。
let id = 21;
let name = "小三";
let age = 23;
// es5.x
const emp = {id: id, name: name, age: age};
console.log(emp);
// es6.x
const emp1 = {id, name, age};
console.log("emp1", emp1);
function test() {
for (let i = 0; i < 10; i++) {
console.log("for in", i);
}
//const name = "xiaosan";
//console.log(name);
//name = "xiaoli";
//console.log("for out", i);
//定义一个对象,const在定义对象时指的是对象的地址不变,对象中属性可以改变
const student = {id: 21, name: "xiaohong", age: 23};
console.log(student);
student.name = "xiaoli";
console.log(student);
student.age = 22;
console.log(student);
//定义一个数组,const在定义数组时指的是数组地址不能改变,但是数组中元素可以改变
const schools = ["北京", "天津"];
console.log(schools);
schools.push("上海");
console.log(schools);
}
test();//调用函数
const app = new Vue({
el: "#app",
data: {
msg: "es6基本语法",
},
methods: {}
})
</script>
8、Vue标准开发方式
Vue推荐开发方式
Vue推荐开发方式是 SPA :Single Page (Web)Application 单页面应用
Vue推荐开发方式是基于单页面应用 单页面web应用
什么是 SPA 单页面应用
单页面应用:就是日后项目中只有一张页面 ====> index.html
为什么 Vue 推荐开发方式为 SPA 的开发方式
- 引入vue.js文件
- 在现有页面中创建vue实例对象
- 一个页面中只能存在一个Vue实例
- Vue推荐开发方式要求:一个应用中只能存在一个Vue实例
使用现有手段严格遵循SPA存在的问题
- 现有开发方式导致项目中唯一一个页面中代码越来越多不利于后续维护
- 现有开发方式导致项目中唯一一个页面中完成全部业务功能,导致当前页面每次加载速度非常慢
为了严格遵循 SPA 开发方式在Vue中提供了 Vue 组件 – Component
- Vue组件
component
减少Vue根实例代码量 - 一个组件负责完成项目中一个功能或者一组功能实现业务功能隔离
- 组件还可以在vue实例中实现复用