**前言:**第一次接触vue组件的时候,迷迷糊糊的,什么组件传值,组件嵌套。。。。应生硬把我饶进去了,现在想想,最大的一个问题就是,开始选的网课不对,虽然评论区中那么多说不行的,但是我还是硬着头皮把视频看完了,结果就是-半吊子,这过了一个多月了,从新找个视频看,老师讲的非常细,之前的很多疑惑点都解开了,下面是这次学习的一点记录
什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可;
组件化和模块化的不同:
- 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
- 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;
vue实例属性
var vm2 = new Vue({
el: '#app2',
data: {},
methods: {},
filters: {},
directives: {},
components: { // 定义实例内部私有组件的
login: {
template: '#tmpl2'
}
},
beforeCreate() { },
created() { },
beforeMount() { },
mounted() { },
beforeUpdate() { },
updated() { },
beforeDestroy() { },
destroyed() { }
})
下面开始记录
导入vue.js
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
一、创建组件的方式
-
创建组件的基本方式
<script> //使用Vue.extend创建一个全局的组件 var com1 = Vue.extend({ template: '<h3>这是使用最笨的方法创建的vue组件</h3>' }) //给创建的组件定义一个名字 Vue.component('mycom1', com1) </script> //在页面中使用创建的组件(注意,要在挂载点标签内使用) <div id="app"> <mycom1></mycom1> </div>
-
处理定义组件时的驼峰命名法
//定义组件的时候使用驼峰命名法 //使用驼峰命名法创建的组件,使用时需要用-进行隔开 var com = Vue.extend({ template: '<h3>使用驼峰命名法进行创建的vue组件</h3>' }) Vue.component('myCom', com) //在页面中使用创建的组件 <div id="app"> <my-com></my-com> </div>
-
将创建组件和命名组件整合在一起
//将创建组件与命名组件整合在一起 Vue.component('mycom3', Vue.extend({ template: '<h3>整合创建组件和命名组件</h3>' })) //在页面中使用创建的组件 <div id="app"> <mycom3></mycom3> </div>
-
再一次简化组件的创建方式,省略Vue.extend()
//再度简化创建组件的方式,采用匿名创建 Vue.component('mycom4', { template: '<h3>匿名创建组件并命名</h3>' }) //在页面中使用创建的组件 <div id="app"> <mycom4></mycom4> </div>
-
使用template标签创建组件(
常用
)<!-- 使用template标签来创建一个组件 --> <template id="mycom5"> <div> 使用template标签来创建一个组件 </div> </template> //给使用template标签创建的组件绑定id并命名 Vue.component('mycom5', { template: '#mycom5' }) //在页面中使用创建的组件 <div id="app"> <mycom5></mycom5> </div>
-
使用template标签创建私有组件
<!-- 使用template标签来创建一个私有的组件 --> <template id="mycom6"> <div> 使用template标签来创建一个组件 </div> </template> // 在vue实例中挂载组件 var vm = new Vue({ el: '#app', data: {}, methods: {}, components: { //在vue实例内部创建一个私有的组件 mycom6: { template: '<div>我是被定义在vue实例内部的一个组件</div>' } } }); //在页面中使用创建的组件 <div id="app"> <mycom5></mycom5> </div>
二、组件中的data和methods
-
组件可以有自己的 data 数据
-
组件的 data 和 实例的 data 有点不一样,实例中的 data 可以为一个对象,但是 组件中的 data 必须是一个方法
-
组件中的 data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行;
-
组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!!
-
在组件中,
data
需要被定义为一个方法,例如:Vue.component('account', { template: '#tmpl', data() { return { msg: '大家好!' } }, methods:{ login(){ alert('点击了登录按钮'); } } });
-
在子组件中,如果将模板字符串,定义到了script标签中,那么,要访问子组件身上的
data
属性中的值,需要使用this
来访问;
为什么组件中的data属性必须定义为一个方法并返回一个对象
-
通过计数器案例演示
-
对象为引用类型,当重用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;
-
而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题,样组件间不会互相干扰
指向一致的data数据
<div id="app"> <num1></num1> <num1></num1> <num1></num1> </div> <!-- 定义组件 --> <template id="tmpl"> <div> <input type="button" value="加1" @click="add"> <h1>{{ count }}</h1> </div> </template> <script> //如果使用全全局的定义, var dataObj = { count:0 } Vue.component('num1', { template: '#tmpl', data(){ return dataObj }, methods:{ add(){ this.count++ } } }); var vm = new Vue({ el:'#app', data:{}, methods:{} }) </script>
指向不一致的data数据
<div id="app"> <count></count> <count></count> <count></count> </div> <template id="count"> <div> <input type="button" value="添加" @click="add()"> <h3>数字:{{count}}</h3> </div> </template> //在组件中创建一个私有函数,一般情况下只能在组件的内部使用 Vue.component('count', { template: '#count', data: function() { return { count: 0 } }, methods: { add() { this.count++ } } })
三、组件之间的切换
//先创建两个组件,然后在两个组件之间进行切换
Vue.component("login", {
template: ' <h3>登录</h3>'
})
Vue.component('register', {
template: ' <h3>注册</h3>'
})
// 创建 Vue 实例,定义两个数据用于进行组件切换
var vm = new Vue({
el: '#app',
data: {
flag: true,
comName: 'login',
},
methods: {}
});
-
使用v-if和v-else进行切换
<div id="app"> <!-- 使用v-if和v-else实现两个组件之间的切换 缺点就是,如果需要切换的组件数量在两个之上,则不能使用这种方法 --> <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>
-
使用component标签中的属性绑定进行组件切换
<component :is="comName"> </component>
-
给组件切换添加动画
<a href="" @click.prevent="comName ='login'">登录</a> <a href="" @click.prevent="comName = 'register'">注册</a> <transition mode="out-in"> <component :is="comName"> </component> </transition> <style> .v-enter, .v-leave-to { opacity: 0; /* 设置透明度 */ transform: translateX(150px); } .v-enter-active, .v-leave-to { position: absolute; transition: all 0.5s ease; } </style>
四、父子组件传值
-
父组件向子组件传值
<div id="app"> <!-- 直接在子组件中调用父组件里面的值,发现失败 --> <!-- // 结论:经过演示,发现,子组件中,默认无法访问到 父组件中的 data 上的数据 和 methods 中的方法 --> <com>{{msg}}</com> <!-- 父组件,可以在引用子组件的时候, 通过 属性绑定(v-bind:) 的形式, 把 需要传递给 子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用 --> <com :son_msg="msg"></com> </div> //在子组件中使用父组件的数据 Vue.component('com', { props: ['son_msg'], data: function() { return { son_msg: "0000" } }, // data 上的数据,都是可读可写的; template: '<div>我是子组件---{{son_msg}}---{{msg}}</div>' }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { msg: '我是父组件里面的数据' }, methods: {} });
-
父组件向子组件传递方法
<div id="app"> 尝试在子组件中直接使用父组件里面的方法 <son></son> 通过绑定方法向子组件传递父组件的方法 <son @son='father'></son> <!-- 在这一步中有一个小细节,绑定的father方法不能在后面加() 在后面加()的含义是将funther方法的执行结果绑定 不加括号的含义是直接绑定的是father方法 --> </div> <script> //创建一个组件,用于获取父组件里面的方法 Vue.component('son', { template: "<div><h3>我是子组件</h3> <input type='button' value='111' @click='son()'></div>", methods: { son() { this.$emit('son') /* 接收父组件传来的方法并调用 */ } } }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: { father() { console.log("我是爸爸") } } }); </script>
-
子组件向父组件传值
思路:
1、父组件有个带参数的函数
2、父组件将函数传递给子组件
3、子组件调用函数并将数据当参数传递给父组件
<div id="app"> <son @son='father'></son> <!-- 在这一步中有一个小细节,绑定的father方法不能在后面加() 在后面加()的含义是将funther方法的执行结果绑定 不加括号的含义是直接绑定的是father方法 --> </div> <script> //创建一个组件,用于获取父组件里面的方法 Vue.component('son', { template: "<div><h3>我是子组件</h3> <input type='button' value='111' @click='son()'></div>", data: function() { return { msg: '我是儿子' } }, methods: { son() { this.$emit('son', this.msg) /* 接收父组件传来的方法并调用 */ } } }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: { father(msg) { console.log("我是爸爸----" + msg) } } }); </script>
五、案例-实现评论功能(Ajax的效果)
分析:发表评论的业务逻辑
-
评论数据存到哪里去???
存放到了 localStorage 中 localStorage.setItem(‘cmts’, ‘’)
-
先组织出一个最新的评论数据对象
-
想办法,把 第二步中,得到的评论对象,保存到 localStorage 中:
-
localStorage 只支持存放字符串数据, 要先调用 JSON.stringify
-
在保存 最新的 评论数据之前,要先从 localStorage获取到之前的评论数据(string), 转换为 一个 数组对象, 然后,把最新的评论, push 到这个数组
-
如果获取到的 localStorage 中的 评论字符串,为空不存在, 则 可以 返回一个 ‘[]’ 让 JSON.parse 去转换
-
把 最新的 评论列表数组,再次调用 JSON.stringify 转为 数组字符串,然后调用 localStorage.setItem()
-
初始化数据的方法在父组件里面,想要在子组件保存完数据之后调用父组件的方法进行刷新数据, 则需要在使用组件时绑定事件,然后在子组件的方法中使用this.$emit(“方法名”),进行使用, 属性绑定时有一个小细节:方法名()表示的是绑定一个方法执行后的结果,不加()表明绑定的是一个方法
<div id="app">
<!-- 评论区 -->
<div class="main">
<!-- 使用发表评论的组件 -->
<tmpl @load="loadComments"></tmpl>
<div class="content" v-for="(item,index) in list" :key="index">
<p>{{item.content}}</p>
留言人:<span>{{item.name}}</span>
</div>
</div>
</div>
<!--发表评论的模板-->
<template id="tmpl">
<div>
<label for="name" >
姓名:<input type="text" id="name" v-model="name">
</label>
<label for="content">
评论内容:
<textarea cols="30" rows="10" id="content" v-model="content"></textarea>
</label>
<label>
<input type="button" value="发表" @click="add" >
</label>
</div>
</template>
<script>
//创建一个发表评论的组件对象
var tmpl = {
template: '#tmpl',
data() {
return {
name: "",
content: "",
}
},
methods: {
//将数据保存至localStorage中
add() {
//创建一个列表对象,用于生成一条新的评论
let listObj = {
id: Date.now(),
name: this.name,
content: this.content
}
//从localStorage中获取全部评论,并使用JSON.parse()转换成json对象
let list = JSON.parse(localStorage.getItem('cmts') || '[]')
//将最新的评论添加至列表中,这里添加在列表的最前面
list.unshift(listObj)
//保存数据
localStorage.setItem('cmts', JSON.stringify(list))
//将用户和内容初始化
this.name = this.content = ""
//刷新页面数据
this.$emit('load')
}
}
}
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
name: '',
content: '',
list: [{
name: 'daidai',
content: '大家好,我是呆呆'
}, {
name: '栋梁',
content: '大家好,我是栋梁'
}]
},
methods: {
//初始化评论列表
loadComments() {
//获取本地存储的数据
let list = JSON.parse(localStorage.getItem('cmts') || '[]')
//将数据赋值给列表
this.list = list
}
},
components: {
tmpl: tmpl,
},
created() {
//在页面数据和方法创建完之后执行该函数
this.loadComments()
},
});
</script>
<style>
.main {
width: 600px;
margin: 100px auto;
}
.content {
border: 1px solid #efeeef;
margin-top: 10px;
}
span {
color: seagreen;
}
</style>
六、使用 this.$refs
来获取元素和组件
<div id="app">
<h3 ref="com">hahahhahaha</h3>
{{msg}}
<button @click="ceshi">...</button>
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
msg: ""
},
methods: {
ceshi() {//获取标签中的值
this.msg = this.$refs.com.innerText
}
},
});
</script>