目录
组件
简介:
通常一个应用会以一棵嵌套的组件树的形式来组织:
全局组件
directives指令
组件:一个小的功能分区
意义:复杂项目拆分简单的组件
让团队开发更高效
组件是可以重复使用的模块
理解:组件其实就是小的Vue,具有data,methods watch computed
组件的定义:
const strper = {template:`<span>...</span>`}
组件注册:
componentd:{steper}
组件的参数传递:
父传子 props
<strper :value="5">
strper内部
props:{type:nuber,default}
steper内部使用 (只读,不修改)
this.value
子传父
在steper内部
this.$emit("numchange",this.num)
numchange事件名称 this,num 事件值
父组件
<steper @numchange="w1=$event">
$event就是子组件通过numchange传递过来的值this.num
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<steper :value="w1" @numchange="w1=$event"></steper><br>
<steper :value="w2" @numchange="w2=$event"></steper><br>
<p :style="{'width':w1+'px','height':w1+'px',borderRadius:w1+'px',border:'1px solid red'}"></p>
<p :style="{'width':w2+'px','height':w2+'px',borderRadius:w2+'px',border:'1px solid green'}"></p>
</div>
<script>
//定义组件
//组件父传子 props(props是只读的)
const steper={
template:`<span>
<button @click="num--">-</button>
<input v-model.number="num" />
<button @click="num++">+</button>
</span>`,
data(){
return{num:this.value}
},
props:{
value:{
type:Number, //value的类型是数字
default:1 //默认值
}
},
watch:{
"num":{
handler:function(nval,oval){
this.$emit("numchange",this.num)
},
deep:true
}
}
}
Vue.createApp({
components:{steper},
data(){
return{
w1:30,
w2:20
}
}
}).mount("#app")
</script>
</body>
</html>
局部组件
const step = {
template:`<div><button @click="n--">-</button>{{n}}<button @click="n++">+</button></div>`,
data(){return {n:1}}
}
注册组件
const app = Vue.createApp({
components:{step}
})
使用组件
<step></step>
<step></step>
props传递参数
对象与数组的默认值必须是函数的返回值
传递
<step :num="10"></step>
<step :num="5"></step>
接收
props:{
"num":{type:Number,default:1}
},
使用
data(){return {n:this.num}}
监听子组件发出的事件
通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop
String
Number
Boolean
Array
Object
Date
Function
symbol
组件的插槽
和 HTML 元素一样,我们经常需要向一个组件传递内容
我们使用 <slot> 作为我们想要插入内容的占位符
<step>
你好,我是嵌套内容
</step>
template:`<div><h1>组件的标题</h1><slot></slot></div>`
具名插槽
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>命名插槽</title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<price>
<template v-slot:pre>
¥
</template>
<template v-slot:next>
元
</template>
</price><br>
<price>
<template v-slot:pre>
$
</template>
<template v-slot:next>
刀
</template>
</price>
</div>
<script>
const price = {
template:`<span><slot name="pre"></slot>100<slot name="next"></slot></span>`
}
Vue.createApp({
components:{
price
},
data(){
}
}).mount("#app")
</script>
</body>
</html>
<!--
插槽
<step>
嵌套内容
</step>
可以通过<slot></slot>获取组件的嵌套内容
命名插槽
<step>
<template>
pre插槽内容
<template>
<step>
<slot name="pre">
插槽的作用域
子
<slot item="item">
父
<step>
<template v-slot:default="scope">
{{scope.item}}
</template>
</step>
directives指令
自定义指令,访问到dom节点
directives:{
"focus":{
mounted(el,binding){
el当前指令所在的dom
binding指令相关信息
binding.value指令的值
}
}
}
钩子函数
created:创建
beforeMount:父组件挂载前
mounted:挂在后
before
计算computed
从现有数据,计算出新的数据(只读)
computed:{
"rmsg":function(){
return this.msg.splice("").reverse().join("")
}
}
-->
作用域插槽
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>命名插槽</title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<ls>
<template v-slot:default="scope">
<span>{{scope.index+1}}列表{{scope.item}}</span>
</template>
</ls>
</div>
<script>
const ls = {
template:`<div>
<p v-for="(item,index) in list">
<slot :item="item" :index="index"></slot>
</p>
</div>`,
data(){
return{
list:["list","react","angular"]
}
}
}
Vue.createApp({
components:{
ls
},
data(){
}
}).mount("#app")
</script>
</body>
</html>
弹框组件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" type="text/css" href="./modal/index.css"/>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<button @click="isShowModal=true">弹框</button>
<button @click="showModal=true">弹框2</button>
<modal :visible="isShowModal" @update:visible="isShowModal=$event"></modal>
<modal :visible="showModal" @update:visible="showModal=$event">
<p>乌拉</p>
</modal>
</div>
<script src="./modal/index.js" type="text/javascript" charset="utf-8"></script>
<script>
Vue.createApp({
components:{
modal
},
data(){
return{
isShowModal:false,
showModal:false
}
}
}).mount("#app")
</script>
</body>
</html>
css
*{
margin: 0;padding: 0;
}
.modal{
width: 100vw;
height: 100vh;
position: relative;
background-color: rgba(0,0,0,.7);
}
.modal-content{
width: 30%;
min-height: 400px;
height: 40%;
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
background-color: #fff;
}
.modal-title{
line-height: 44px;
display: flex;
justify-content: space-between;
}
.modal-body{
padding: 10px;
}
js
const modal={
template:`
<div class="modal" v-if="visible">
<div class="modal-content">
<div class="modal-title"><span>我是标题</span>
<span
@click="$emit('update:visible',false)">×</span></div>
<div class="modal-body">
<slot></slot>
</div>
</div>
</div>
`,
props:{
"visible":{type:Boolean,default:false}
}
}
动画transition
动画
Vue 提供了内置的过渡封装组件,该组件用于包裹要实现过渡效果的组件。组件进入和离开 DOM 的钩子 使用内置的 <transition> 组件
<button @click="flag=!flag">切换</button> <br>
<transition name="fade">
<img src="./images/sun.jpeg" alt="" width="120" v-if="flag">
</transition>
动画-过渡class
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
.fade-enter-active,
.fade-leave-active{
/* 整个进入的过程
整个离开的过程都拥有这两个类*/
transition: all ease 1s;
}
/* 进入状态的class */
.fade-enter-from{
opacity: 0;
}
/* 进入结束的class */
.fade-enter-to{
opacity: 1;
}
/* 离开开始状态 */
.fade-leave-from{
opacity: 1;
}
/* 离开结束状态 */
.fade-leave-to{
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<button @click="flag=!flag">切换</button><br>
<transition name="fade">
<img src="img/sun.jpeg" v-if="flag">
</transition>
</div>
<script>
// 1 Vue动画是通过组件,transition实现的
// 2 在显示离开产生动画 v-if v-show v-else v-else-if
Vue.createApp({
data(){
return{flag:true}
}
}).mount("#app")
</script>
<!--
动画<transition></transition>
自动对显示与隐藏的元素添加类名
v-enter-active进入整个过程
.v-enter-from进入开始状态
.v-enter-to进入结束状态
.v-leave-active离开的过程
.v-leave-from离开开始状态
.v-leave-to离开结束状态
transition
mode模式
in-out
out-in
name名称
enter-active-class
自定义进入class名称
leave-active-class
自定义离开class名称
transition-group
tag包裹标签名
.v-move
正在移动的元素
-->
</body>
</html>
动画-使用关键帧动画
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
@keyframes fadeIn{
0%{opacity: 0;transform: rotate(-180deg);}
100%o{opacity: 1;transform: rotate(0);}
}
@keyframes fadeOut{
0%{opacity: 1;transform: rotate(0);}
100%{opacity: 0;transform: rotate(180deg);}
}
.fade-enter-active{
animation: fadeIn ease 1s;
}
.fade-leave-active{
animation: fadeOut ease 1s;
}
</style>
</head>
<body>
<div id="app">
<button @click="flag=!flag">切换</button><br>
<transition name="fade">
<img src="img/sun.jpeg" v-if="flag">
</transition>
</div>
<script>
// 1 Vue动画是通过组件,transition实现的
// 2 在显示离开产生动画 v-if v-show v-else v-else-if
Vue.createApp({
data(){
return{flag:true}
}
}).mount("#app")
</script>
<!--
动画<transition></transition>
自动对显示与隐藏的元素添加类名
v-enter-active进入整个过程
.v-enter-from进入开始状态
.v-enter-to进入结束状态
.v-leave-active离开的过程
.v-leave-from离开开始状态
.v-leave-to离开结束状态
-->
</body>
</html>
动画-引入第三方
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href="./css/animate.css"/>
</head>
<body>
<div id="app">
<button @click="flag=!flag">切换</button><br>
<transition name="fade" enter-active-class="flipInY animated" leave-active-class="hinge animated">
<img src="img/sun.jpeg" v-if="flag">
</transition>
</div>
<script>
// 1 Vue动画是通过组件,transition实现的
// 2 在显示离开产生动画 v-if v-show v-else v-else-if
Vue.createApp({
data(){
return{flag:true}
}
}).mount("#app")
</script>
<!--
动画<transition></transition>
自动对显示与隐藏的元素添加类名
v-enter-active进入整个过程
.v-enter-from进入开始状态
.v-enter-to进入结束状态
.v-leave-active离开的过程
.v-leave-from离开开始状态
.v-leave-to离开结束状态
-->
</body>
</html>
动画模式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href="./css/animate.css"/>
<style type="text/css">
body{
padding: 50px;
}
p button{
position: absolute;
left: 0;
animation-duration: .3s !important;
}
</style>
</head>
<body>
<div id="app">
<button @click="flag=!flag">切换</button><br>
<p style="position: relative;">
<!-- out-in先出后进 in-out先进后出 -->
<transition name="fade" mode="in-out" enter-active-class="slideInRight animated" leave-active-class="slideOutLeft animated">
<button v-if="flag">进</button>
<button v-else>出</button>
</transition>
</p>
</div>
<script>
// 1 Vue动画是通过组件,transition实现的
// 2 在显示离开产生动画 v-if v-show v-else v-else-if
Vue.createApp({
data(){
return{flag:true}
}
}).mount("#app")
</script>
<!--
动画<transition></transition>
自动对显示与隐藏的元素添加类名
v-enter-active进入整个过程
.v-enter-from进入开始状态
.v-enter-to进入结束状态
.v-leave-active离开的过程
.v-leave-from离开开始状态
.v-leave-to离开结束状态
-->
</body>
</html>
列表过渡
我们会使用 <transition-group> 组件实现列表过渡
<transition-group tag="div" name="slide" >
<div class="item" v-for="item in undoList" :key="item.name">
.....
</transition-group>
.slide-leave-active{
animation: slideOut ease 1s;
position: absolute;
}
/* transition-group 正在移动中的类名 */
/* 移动中的元素 */
.slide-move{
transition: all ease 1s;
}