今日总结
一、vue组件
什么是组件:组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可。
组块化和模块化的不同:
模块化:是从代码的逻辑角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一(实现 高内聚低耦合 模块之间低耦合 模块内部高内聚)
组块化:是从UI界面的角度进行划分;前端的组件化,方便UI组件的重用
1、全局组件定义的四种方式
1、使用 Vue.extend 配合 Vue.component 方法:
2、直接使用 Vue.component 方法:
3、将模板字符串定义到 script 标签中,同时需要使用 Vue.component 来定义组件
4、将模板字符串定义到 template 标签中,同时需要使用 Vue.component 来定义组件
注意:组件中的 DOM 结构,有且只能有唯一的根元素来进行包裹
组件名不能和 h5 标签重复 不使用内置或保留的HTML元素作为组件id
标签名不区分大小写 注意不能使用驼峰命名法
示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>全局定义组件定义的四种方式</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id='app'>
<!-- 1 -->
<login></login>
<!-- 2 -->
<register></register>
<!-- 3 -->
<tmpl></tmpl>
<!-- 4 -->
<account></account>
</div>
<!-- 3 -->
<script id="tmpl" type="x-template">
<div><a href="#">登录</a> | <a href="#">注册</a></div>
</script>
<!-- 4 -->
<template id="account">
<div>
<p>我是一个p标签</p>
</div>
<!-- 注意:组件中的DOM结构,有且只能有唯一的根元素 -->
<!-- <div>
<strong>我是一个Vue组件</strong>
</div> -->
</template>
<script>
// 组件名不能和 h5 标签重复 不使用内置或保留的HTML元素作为组件id
// 标签名不区分大小写 注意不能使用驼峰命名法
// 1、使用 Vue.extend 配合 Vue.component 方法
var login = Vue.extend({ // 全局声明
template:'<h1>登录</h1>'
})
Vue.component('login',login) // 全局注册 (名字 模板)
// 2、直接使用 Vue.component 方法
Vue.component('register',{
template:'<h2>注册</h2>'
})
// 3、将模板字符串,定义到 script 标签中
// 同时,需要使用 Vue.component 来定义组件
Vue.component('tmpl',{
template:'#tmpl'
})
// 4、以上三种方法现在不怎么用了,通常使用下面的使用方法
// 将模板字符串定义到template标签中
Vue.component('account',{
template:'#account'
})
let vm = new Vue({
el: '#app',
data: {
},
methods: {
},
})
</script>
</body>
</html>
2、使用components属性定义局部子组件(私有组件)
components与methods、data同级
let vm = new Vue({
el: '#app',
data: {
},
methods: {
},
// 私有定义方式
components:{
'myheader':{ // 名字
template:'#myheader' // 模板
}
}
})
示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>私有组件</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id='app'>
<!-- 4 -->
<myheader></myheader>
</div>
<!-- 4 -->
<template id="myheader">
<div>
<p>我是一个p标签</p>
<p>我是一个p标签</p>
<p>我是一个p标签</p>
</div>
<!-- 注意:组件中的DOM结构,有且只能有唯一的根元素 -->
<!-- <div>
<strong>我是一个Vue组件</strong>
</div> -->
</template>
<script>
// 标签名不区分大小写 注意不能使用驼峰命名法
// 4、
// 将模板字符串定义到template标签中
// Vue.component('account',{
// template:'#account'
// })
let vm = new Vue({
el: '#app',
data: {
},
methods: {
},
// 私有定义方式
components:{
'myheader':{ // 名字
template:'#myheader' // 模板
}
}
})
</script>
</body>
</html>
3、组件中展示数据和响应事件
在组件中,data需要被定义为一个方法
为什么?
因为要实现数据隔离
示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id='app'>
<button @click="flag = !flag"> 点我 </button>
<!-- 子组件的应用 -->
<component is="mine"></component>
<component :is="flag?'login':'mine'"></component>
</div>
<!-- 4 -->
<template id="login">
<div>
登录
</div>
</template>
<template id="mine">
<div>
用户名
</div>
</template>
<script>
Vue.component('mine',{
template:'#mine',
})
// 全局定义组件
Vue.component('login',{
template:'#login',
// 为什么组件中的data属性必须定义为一个方法并返回一个对象
// 要 数据隔离
data(){
return {
msg:'hello',
num:6
}
},
methods:{
addn(n){
this.num += n
}
},
beforeCreate(){
console.log('beforeCreate');
},
created(){
console.log('created');
},
beforeDestroy(){
console.log('beforeDestroy');
},
destroyed(){
console.log('destroyed');
},
})
let vm = new Vue({
el: '#app',
data: {
flag:true,
},
methods: {
},
})
</script>
</body>
</html>
4、使用 :is 属性来切换不同的子组件,并添加切换动画
使用 component 标签,来引用组件,并通过 :is 属性来确定要加载的组件
示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.v-leave-to,
.v-enter{
opacity: 0;
transform: translateX(200px);
}
.v-enter-to,
.v-leave{
opacity: 1;
transform: translateX(0px);
}
.v-enter-active,
.v-leave-active{
transition: all 2s;
}
div{
width: 100px;
}
</style>
</head>
<body>
<div id='app'>
<button @click="flag = !flag"> 点我 </button>
<!-- 子组件的应用 -->
<component is="mine"></component>
<!-- <component :is="flag?'login':'mine'"></component> -->
组件动画 1
<transition mode="out-in">
<component :is="flag?'login':'mine'"></component>
</transition>
<br>
<br>
<br>
<br>
组件动画 2
<transition mode="out-in">
<!-- <component :is="flag?'login':'mine'"></component> -->
<login v-if="flag"></login>
<mine v-else></mine>
</transition>
</div>
<!-- 4 -->
<template id="login">
<div>
登录
</div>
</template>
<template id="mine">
<div>
用户名
</div>
</template>
<script>
Vue.component('mine',{
template:'#mine',
})
// 全局定义组件
Vue.component('login',{
template:'#login',
// 为什么组件中的data属性必须定义为一个方法并返回一个对象
// 要 数据隔离
data(){
return {
msg:'hello',
num:6
}
},
methods:{
addn(n){
this.num += n
}
},
beforeCreate(){
console.log('beforeCreate');
},
created(){
console.log('created');
},
beforeDestroy(){
console.log('beforeDestroy');
},
destroyed(){
console.log('destroyed');
},
})
let vm = new Vue({
el: '#app',
data: {
flag:true,
},
methods: {
},
})
</script>
</body>
</html>
5、组件传值:父传子
<body>
<div id='app'>
<!-- 1、接受来自父亲的变量和函数,注意不要和子组件data中的变量重名 -->
<test :weather="weather" :func="log_father" text="今天是个什么天气">天气
<template v-slot:yang>
<!-- <p v-text="msg"></p> --> <!-- 报错原因:此处写的 msg 是父的变量,不是子的变量 -->
</template>
</test>
</div>
<template id="test">
<!-- 3、在子组件中进行使用 -->
<!-- 传过来之后,使用方法就和在子组件中data和methods相同,但是不能修改,要修改的话要在父亲中修改 -->
<div>
<slot></slot>
<h1>我是子组件</h1>
<button @click="log1"> 点我 </button> <!-- 在子组件中写的事件和变量,是来自子组件的事件变量 -->
<!-- 插槽 -->
<slot name="yang"></slot>
<!-- weather为父亲传过来的值 -->
<p v-text="weather"></p> <!-- 变量父传子之后,在子组件中就可以使用父组件的变量和函数了 -->
<!-- func为父亲传过来的函数 -->
<button @click="func">来自父亲的事件</button>
</div>
</template>
<!--
总结一下:真的很像继承
在进行组件间父传子(变量和函数)时,1,2,3 + 注意
-->
<script>
const vm = new Vue({
el: '#app',
data: {
weather:'sun'
},
methods: {
log_father(){
console.log('我是父亲');
}
},
components:{ // 定义私有子组件
test:{ // 子组件的名字
template:'#test', // 子组建的模板
data(){
return {
type:'good',
msg:'',
}
},
// 2、接受变量和函数,确定接收到变量和方法的数据类型
props:{
weather:String,
text:String,
func:Function,
},
// 传过来之后,使用方法就和在子组件中data和methods相同,但是不能修改,要修改的话要在父亲中修改
methods:{
log1(){
console.log(this.text);
console.log(this.weather);
this.msg = this.weather
console.log(this.type);
}
},
}
}
})
</script>
</body>
二、slot插槽
1、插槽的使用
在子组件中放一个占位符 <slot></slot>
在父组件中给这个占位符填充内容
如果子组件不使用插槽的话,父组件如果需要往子组件中填充模板后者html是没有办法做到的
2、插槽的使用-具名插槽
具名插槽就是给插槽取个名字,一个子组件可以放多个插槽,而且可以放在不同的地方,二负组件填充内容是,可以根据这个名字把内容填充到对应的插槽中
父组件填充内容,父组件通过 v-slot:name 的方式指定到对应的插槽中
子组件在写插槽时,加上name属性
3、插槽的使用-默认插槽
默认插槽就是指没有名字的插槽,子组件未定义的名字的插槽,父级将会把 未指定插槽的填充的内容填充到默认插槽中。
示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>插槽</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
<style>
ul{
display: flex;
justify-content: space-between;
flex-wrap: wrap;
list-style: none;
}
li{
width: 19%;
}
li img{
width: 100%;
height: 120px;
}
h2{
text-align: center;
}
</style>
</head>
<body>
<div id='app'>
<!-- 免费课程 -->
<course :type="type" page-size="10">
免费 <!--默认插槽-->
<template v-slot:fee>免费</template>
</course>
<!-- 精品课程 -->
<course type="boutique">
精品
<template v-slot:fee>
<p>
我是精品课程
</p>
</template>
</course>
<!-- 折扣课程 -->
<course type="discount">
限时折扣
<template v-slot:fee>
<p>
我是折扣课程
<!-- {{item.coursePrice}} -->
</p>
</template>
</course>
</div>
<template id="course">
<div>
<h2><slot><!--默认插槽--></slot>课程</h2>
<ul>
<li v-for="item in freeCourseList" :key="item.id">
<img :src="item.bannerFileUrl" alt="">
<div>{{item.courseTitle}}</div>
<div>共 {{item.learningNum}} 节课 | {{item.participationsCount}} 人报名</div>
<div><slot name="fee"></slot></div>
</li>
</ul>
</div>
</template>
<script>
Vue.component('course',{
template:'#course',
data(){
return {
freeCourseList:[]
}
},
// 接受传值
props:{
// 自己定义接受
type:String,
size:Number,
// pageSize:Number,
// 定义多个数据类型
// pageSize:[Number,String],
pageSize:{
type:[Number,String],
// default:5,
// 注意默认参数使用引用类型时,default要写成函数返回值的形式:用于数据隔离
default(){
return 5
}
}
},
methods:{
getCourseList(type='free',pageNum=1,pageSize=5){
let formurl = new URLSearchParams();
formurl.append("type", type);
formurl.append("pageNum", pageSize);
formurl.append("pageSize", pageNum);
return axios.post("http://1.117.81.216:8086/weChat/applet/course/list/type", formurl);
}
},
created(){
console.log(this);
console.log(this.pageSize); // 数据的父传子 可读不可改
this.getCourseList(this.type,this.pageSize,1).then(res=>{
this.freeCourseList = res.data.rows
})
}
})
const vm = new Vue({
el: '#app',
data: {
type:'free'
},
methods: {
},
})
</script>
</body>
</html>
其他
1、vue动画通过 v-if v-show 来pending动画的内容,以此来控制动画的产生
2、一个好用的第三方动画库 animate.css 需要引入文件,之后直接在<transition>标签中使用类名即可
3、<transition>标签中的 mode 属性只能识别组件,不能直接识别标签
<transition mode="out-in">
<component :is="flag?'login':'mine'"></component>
</transition>
单词
1、component 组件
2、template 模板
3、props 接受传值