前端学习之Vue组件
一、组件
- 每一个组件都是一个vue实例(对象)
- new Vue()产生的也是实例(对象),所以也是组件,我们称之为 根组件
- 每个组件均具有自身的模板template,根组件的模板就是挂载点
- 每个组件模板只能拥有一个根标签
- 子组件的数据具有作用域,以达到组件的复用
1.1 根组件
<div id="app">
<!-- {{ msg }}-->
</div>
<script src="../vue_lib/vue.js"></script>
<script>
/**
* 1、组件:由html、css、js三部分组成的独立单位,可以类似于变量,重复使用
* 2、组件其实就是vue实例(对象),一个组件就是一个vue实例(对象)
* 3、new Vue()产生的也是实例(对象),所以也是组件,我们称之为 根组件
* 一个页面建议只出现一个根组件(项目开发模式下,一个项目建议只出现一个根组件)
* 4、组件的html页面结构有 template 实例成员提供
* template提供的html结构是用来构虚拟DOM
* 真实DOM最终会被虚拟DOM替换
* 根组件一般不提供template,就由挂载点el来提供构建虚拟DOM的页面结构,根组件如果提供了template,还需要设置挂载点作为替换占位
* template模板有且只有一个根标签
*/
let c1 = '';
new Vue({
el: '#app',
data: {
msg: '12345',
c1: 'red'
},
template: `
<div id="app">
<p :style="{color: c1}">{{ msg }}</p>
<p @click="clickAction">{{ msg }}</p>
</div>
`,
methods: {
clickAction() {
console.log(this.msg)
}
}
})
</script>
1.2 子组件
-
定义组件
// 如何定义子组件:组件就是一个普通对象,内部采用vue语法结构,被vue注册解释后,就会成为vue组件 let myTag = { template: ` <div> <h3>子组件</h3> <p>我是自定义的子组件</p> </div> `, };
-
注册组件
new Vue({ el:"#app", // 注册组件 components:{ // 'my-tag': myTag, // myTag: myTag, //JS语法中不识别-,用驼峰表示 myTag, // 简写 } })
-
使用组件
<!--根组件的template--> <div id="app"> <!--在根组件template中加载的组件,称之为根组件的子组件--> <!-- 使用组件--> <my-tag></my-tag> <my-tag></my-tag> <my-tag></my-tag> </div>
<body>
<!--根组件的template-->
<div id="app">
<!--在根组件template中加载的组件,称之为根组件的子组件-->
<!-- 使用组件-->
<my-tag></my-tag>
<my-tag></my-tag>
<my-tag></my-tag>
<tag></tag>
</div>
</body>
<script src="../vue_lib/vue.js"></script>
<script>
// 1、定义组件
// 2、注册组件
// 3、使用组件
// 如何定义子组件:组件就是一个普通对象,内部采用vue语法结构,被vue注册解释后,就会成为vue组件
let myTag = {
template: `
<div>
<h3>子组件</h3>
<p>我是自定义的子组件</p>
</div>
`,
};
new Vue({
el:"#app",
// 注册组件
components:{
// 'my-tag': myTag,
// myTag: myTag, //JS语法中不识别-,用驼峰表示
myTag, // 简写
}
})
</script>
1.3 全局组件(了解)
- 了解:全局组件,不要注册就可以直接使用
<!--根组件的template-->
<div id="app">
<tag></tag>
</div>
// 了解:全局组件,不要注册就可以直接使用
Vue.component('tag', {
template: `
<div>
<h3>全局组件</h3>
<p>我是自定义的全局组件</p>
</div>
`,
});
二、组件传参
一般一个模板只有一个根组件,可以有很多子组件,但是有些地方需要父子之间相互传参,下面就介绍组件之间如何传参。
2.1 子组件数据的局部化处理
当对一个组件复用时会有一个问题,就是每个组件如何保存和使用自己组件的数据。
- 能被复用的组件(除了根组件),数据都要做局部化处理,因为复用组件后,组件的数据是相互独立的
- 方法的作用域是局部的,因此data可以变成一个方法,返回值是一个字典,里面是数据
- data的值为绑定的方法的返回值,返回值是存放数据的字典
<head>
<meta charset="UTF-8">
<title>子组件数据的局部化处理</title>
<style>
.wrap {
width: calc(200px * 4 + 80px);
margin: 0 auto;
user-select: none;
}
.box {
width: 200px;
height: 260px;
/*border: 1px solid black;*/
background-color: rgba(10, 200, 30, 0.5);
border-radius: 10px;
float: left;
margin: 10px;
}
.box img {
width: 100%;
/*height: 200px;*/
border-radius: 50%;
}
.box p {
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<div class="wrap">
<!-- 使用组件-->
<tag></tag>
<tag></tag>
<tag></tag>
<tag></tag>
</div>
</div>
</body>
<script src="../vue_lib/vue.js"></script>
<script>
// 再定义子组件
let titleTag ={
template:`
<h1>你好</h1>
`,
};
// 定义子组件
let tag = {
template:`
<div class="box" @click="fn">
<img src="../001.png">
<title-tag></title-tag>
<p >
锤它:<b>{{ num }}下</b>
</p>
</div>
`,
// 能被复用的组件(除了根组件),数据都要做局部化处理,因为复用组件后,组件的数据是相互独立的
// data的值为绑定的方法的返回值,返回值是存放数据的字典
data (){ // 固定格式
return {
num:0,
}
},
methods: {
fn() {
this.num ++
}
},
components:{
// 在子组件中注册组件
titleTag,
}
};
new Vue({
el:"#app",
components:{
// 注册组件
tag,
},
})
</script>
2.2 父组件给子组件传参
- 父组件在标签中通过自定义属性传参,属性名就是子组件接收到的名字,value是父组件中的数据
- 子组件通过
props
来反射接收父组件的值
<head>
<meta charset="UTF-8">
<title>组件传参-父传子</title>
<style>
.wrap {
width: calc(200px * 4 + 80px);
margin: 0 auto;
user-select: none;
}
.box {
width: 200px;
height: 260px;
/*border: 1px solid black;*/
background-color: rgba(10, 200, 30, 0.5);
border-radius: 10px;
float: left;
margin: 10px;
}
.box img {
width: 100%;
/*height: 200px;*/
border-radius: 50%;
}
.box p {
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<div class="wrap">
<!--使用组件,给子组件传参-->
<tag v-for="dog in dogs" v-bind:dog="dog"/>
</div>
</div>
</body>
<script src="../vue_lib/vue.js"></script>
<script>
let dogs = [
{ title: '二哈1号', img: '../001.png', },
{ title: '二哈2号', img: '../001.png', },
{ title: '二哈3号', img: '../001.png', },
{ title: '二哈4号', img: '../001.png', },
{ title: '二哈1号', img: '../001.png', },
{ title: '二哈2号', img: '../001.png', },
{ title: '二哈3号', img: '../001.png', },
{ title: '二哈4号', img: '../001.png', },
];
// 定义子组件
let tag = {
// 通过反射接收父组件的传参,就可以直接用了
props: ["dog",],
template:`
<div class="box" @click="fn">
<b>{{ dog.title }}</b>
<img :src="dog.img">
<p >
锤它:<b>{{ num }}下</b>
</p>
</div>
`,
// 能被复用的组件(除了根组件),数据都要做局部化处理,因为复用组件后,组件的数据是相互独立的
// data的值为绑定的方法的返回值,返回值是存放数据的字典
data (){ // 固定格式
return {
// 自己需要用的参数 就在这里写
num:0,
}
},
methods: {
fn() {
this.num ++
}
},
};
new Vue({
el:"#app",
data : {
dogs,
},
components:{
// 注册组件
tag,
},
});
</script>
总结
- 数据在父组件中产生,在父组件中渲染子组件,子组件绑定自定义属性,附上父组件中的数据
- 子组件自定义属性在子组件的props成员中进行声明(采用字符串发射机制)
- 在子组件内部,就可以用props声明的属性(直接作为变量)来使用父组件中的数据
2.3 子组件给父组件传参(了解)
子组件给父组件传参不是很好理解,主要看例子
- **子组件通过
this.$emit('父组件标签中的名字', '参数');**
<head>
<meta charset="UTF-8">
<title>组件传参-子传父</title>
<style>
ul {
list-style: none;
}
.d-btn {
font-size: 12px;
width: 15px;
display: inline-block;
}
.d-btn:hover {
color: red;
cursor: pointer;
}
</style>
</head>
<body>
<div id="app">
<input type="text" v-model="msg">
<button @click="send_comment">留言</button>
<ul>
<!-- 这里的标签会被子组件中的虚拟DOM替换,但是在渲染是依然会先循环生成很多标签并给子组件传参和接收传参-->
<tag v-for="(v, i) in comment_list" :msg="v" :index="i" @f1="deleteMsg"/>
</ul>
</div>
</body>
<script src="../vue_lib/vue.js"></script>
<script>
// 子组件
let tag ={
props : ["msg","index"],
template:`
<li @click="fn">{{ msg }}</li>
`,
methods: {
fn(){
// 点击子集,要告诉父级删除第几条数据,因为comments在父级中
// 需要通知父级
this.$emit('f1', this.index);
},
}
};
// 根组件
new Vue({
el:"#app",
data : {
msg : "",
comment_list : localStorage.comments ? JSON.parse(localStorage.comments): [],
},
methods:{
send_comment(){
if(this.msg){
this.comment_list.push(this.msg);
this.msg = "";
// 序列化后 存到前台数据库
localStorage.comments = JSON.stringify(this.comment_list)
}
},
deleteMsg(index){
// 根据索引来删除
this.comment_list.splice(index,1);
// 序列化后 存到前台数据库
localStorage.comments = JSON.stringify(this.comment_list)
}
},
components:{
tag,
}
})
</script>
<script>
/* 演示 */
// localStorage,sessionStorage不能直接存储数组和对象,需要序列化为json
localStorage.arr = JSON.stringify([1, 2, 3]);
let res = JSON.parse(localStorage.arr);
console.log(res, res[2]);
</script>