Version: Next

11. Vue组件——Component

11.1 组件的作用

用来减少Vue实例对象中的代码量,在开发中可以根据不同的业务功能将页面划分为不同的多个组件,由多个组件完成整个页面的布局,便于在Vue开发中管理页面,也便于维护

11.2 组件的使用

全局注册

注册给Vue实例,全局唯一,可以在Vue作用范围内的任何位置使用

Vue.component(组件名称,{配置对象})属性

  • 组件名称:驼峰命名会被Vue更改

  • userLogin -> user-login

  • 配置对象参数

    • template:用来书写组件的html模板、html代码,再template中,必须存在一个容器

使用

  • body标签中直接使用名为组件名的标签
  • 驼峰命名会被Vue更改 <userLogin> -> <user-login>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<login></login>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
Vue.component('login',{
template:'<div><h1>用户登录</h1></div>'
});
const vue = new Vue({
el:"#app",
data:{},
methods:{}
})
</script>
</body>
</html>

局部注册

全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。

通过将组件注册给对一个的Vue实例中的一个component属性来完成的组件注册,这种方式不会对Vue实例造成体量增加

方式一

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<login></login>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
//局部组件,登陆模板声明
let login = {
template: '<div><h1>用户登录</h1></div>'
}
const vue = new Vue({
el: "#app",
data: {},
methods: {},
components: { //真正注册组件
login: login //组件名:组件体
}
})
</script>
</body>
</html>

方式二

  • template标签定义模板,定义id属性,根据选择器选择模板
  • 模板要定义在Vue作用范围外
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<login></login>
</div>
<template id="loginTemplate">
<h1>用户登录!</h1>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
//局部组件,登陆模板
let login = {
template: '#loginTemplate'
}
const vue = new Vue({
el: "#app",
data: {},
methods: {},
components: {
login: login //组件名:组件体
}
})
</script>
</body>
</html>

11.3 组件的prop属性

作用:用来给组件传递响应的静态数据或动态数据

11.3.1 静态传值

通过在组件上声明静态数据传递给组件内部

  1. 声明组件的配置对象,使用props数组接收使用组件时,通过组件标签定义的属性
  2. template中渲染接收到的数据
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<login person-name="张老板" age='23'></login>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
//声明一个组件的配置对象
let login = {
template: '<div><h1>欢迎:{{personName}} 年龄:{{age}}</h1></div>',
props: ['personName', 'age']
}
const vue = new Vue({
el: "#app",
data: {},
methods: {},
components: {
login: login //组件名:组件体
}
})
</script>
</body>
</html>

11.3.2 动态传值

Vue实例相当于父组件,形成父组件给子组件传值的过程

  • 声明组件的配置对象,使用props数组接收使用组件时,通过组件标签定义的属性,将该属性通过v-bind:绑定到Vue实例data
  • 修改data域中的值,则模板中的值会通过props被修改
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<login :person-name="name" :age='age'></login>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
//声明一个组件的配置对象
const login = {
template: '<div><h1>欢迎:{{personName}} 年龄:{{age}}</h1></div>',
props: ['personName', 'age']
}
const vue = new Vue({
el: "#app",
data: {
name:"哈哈",
age:25
},
methods: {},
components: {
login: login //组件名:组件体
}
})
</script>
</body>
</html>

11.3.3 单向数据流

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<login :username="username"></login>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
const login = {
template: '<div><h1>欢迎:{{name}} | {{username}}</h1></div>',
data() {
return {
name: "小黑黑"
};
},
props: ['username']
}
const vue = new Vue({
el: "#app",
data: {
username: "老王"
},
methods: {},
components: {
login: login //组件名:组件体
}
})
</script>
</body>
</html>

11.3.4 组件定义数据、事件

组件中定义内部数据

组件自己的属性,默认属性,以函数的形式返回

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<login :username="username"></login>
</div>
<template id='t'>
<div>
<h1>名字 -> {{msg}}</h1>
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
const login = {
template: '#t',
data() {
return {
msg: 'hello', ////组件内部数据
list: ['java', 'spring', 'springboot']
}
}
}
const vue = new Vue({
el: "#app",
data: {
username: "老王"
},
methods: {},
components: {
login: login //组件名:组件体
}
})
</script>
</body>
</html>

组件中定义事件

  • 组件中定义事件和在Vue实例中定义事件基本一致,直接在组件内部对应html代码上加@事件名=函数名即可
  • 在组件内部使用method属性来定义对应的时间函数即可,事件函数中this指向的是当前组件的实例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<login :username="username"></login>
</div>
<template id='t'>
<div>
<input type="button" value="点我" @click="change" />
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
const login = {
template: '#t',
data() {
return {
name: "Alice"
}
},
methods: {
change() {
alert(this.name); //打印组件内部name数据
}
}
}
const vue = new Vue({
el: "#app",
data: {
username: "老王"
},
methods: {},
components: {
login: login //组件名:组件体
}
})
</script>
</body>
</html>

11.3.5 子组件传递事件与调用

子组件使用定义在父组件中的事件或函数,父组件的事件传递给子组件,并在子组件中调用

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<!--1. 在login组件上注册aaa事件,其内部调用Vue实例的findAll函数 -->
<login :username="username" @aaa="findAll"></login>
</div>
<template id='t'>
<div>
<h1>{{uname}}</h1>
<input type="button" value="点我" :username="username" @click="change" />
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
const login = {
template: '#t',
data() {
return {
uname: this.username
}
},
props: ['username'],
methods: {
change(){
// 调用vue实例中的函数
// 2. 在组件中使用`$emit('事件名')`调用传递进来的父方法
this.$emit('aaa')
}
}
}
const vue = new Vue({
el: "#app",
data: {
username: "老王"
},
methods: {
findAll(){
alert("vue实例中的方法");
}
},
components: {
login: login //组件名:组件体
}
})
</script>
</body>
</html>