过渡效果组件
- 组件名:transition
- 组件名:transition-group
- 作用:用于为vue项目中 组件、路由、页面提供通过vue语法控制切换过程中的css 动画
vue 提供动画组件通过包裹元素方式,实现主动监控根元素vue语法执行的同时增加合理的延迟实现自定义动画操作
+ 动画组件可以配合 v-if v-show 动态组件 路由组件 ……
+ CSS 动画从方向上分为两种,每种三过程
1. 从不显示到显示(进入)enter
a.不显示时的样式 from
b.css动画的执行过程 active
c.显示时的样式 to
2. 从显示到不显示(离开)leave
a.显示时的样式 from
b.css动画的执行过程 active
c.不显示时的样式 to
<Transition> 只用于一个根元素的动画监控
<TransitionGroup> 用于多个根元素的动画分别监控 (必须为所有内部的元素提供key)
特殊属性
:appear="true" // 开启默认的进入动画执行
appear-from-class="hide2"
appear-active-class="active"
appear-to-class="show2"
<style>
body{
padding-bottom: 800px;
}
.box{
width: 400px;
height: 200px;
background-color: brown;
color: white;
}
.show{
opacity: 1;
}
.show1{
width: 400px;
}
.active{
transition: all ease 2s;
}
.hide{
opacity: 0;
}
.hide1{
width: 0px;
}
ul{
overflow: hidden;
}
li{
margin: 10px;
background-color: paleturquoise;
width: 300px;
}
.show2{
transform: translate(0%,0px);
}
.hide2{
transform: translate(100%,0px);
}
</style>
</head>
<body>
<div id="app">
<input type="button" value="flag=!flag" @click="flag=!flag">
<br><br>
<transition
:appear="true"
appear-from-class="hide2"
appear-active-class="active"
appear-to-class="show2"
leave-from-class="show"
leave-active-class="active"
leave-to-class="hide"
enter-from-class="hide1"
enter-active-class="active"
enter-to-class="show1"
>
<div v-if="flag" class="box">页面</div>
</transition>
<hr>
<input type="button" value="addItem" @click="arr.push( Math.random() )">
<ul>
<transition-group
enter-from-class="hide2"
enter-active-class="active"
enter-to-class="show2"
@after-enter="showTip()"
>
<li v-for="(item, index) in arr" :key="item">{{ item }}</li>
</transition-group>
</ul>
</div>
<script type="module">
import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
createApp({
data(){
return {
flag:true,
arr:[1,2,3,4,5]
}
},
methods: {
showTip(){
alert("添加完成")
}
},
}).mount("#app")
</script>
外部动画的应用:Animate的应用
<link rel="stylesheet" href="../../assets/animate/animate.css">
<style>
body{
padding-bottom: 800px;
}
.box{
width: 400px;
height: 300px;
background-color: brown;
}
</style>
</head>
<body>
<div id="app">
<input type="button" value="flag=!flag" @click="flag=!flag">
<br><br>
<transition
enter-active-class="animate__animated animate__fadeInRight"
leave-active-class="animate__animated animate__fadeOutLeft"
>
<div v-if="flag" class="box"></div>
</transition>
</div>
<script type="module">
import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
createApp({
data(){
return {
flag:true
}
}
}).mount("#app")
</script>
红色标记部分为该css引用文件自带,后面为Animate动画名称
组件分发
- 组件名:slot :
- 作用:针对于组件定义时的内部模板结构的操作,==主要在组件开发时,如果模板存在一部分页面代码无法确定,可以通过slot 定义页面占位,当组件调用时,可以通过标签中定义 新的内容,完成 slot 的内容补充==
- 涉及属性: v-slot 指令
<!--
vue语法中分发的意思是:在组件页面结构定义时,存在部分不确定的页面结构或者取值时,
可通过特殊占位标签 <slot> 进行位置定义,当该组件被使用时,
通过组件标签中填充的页面内容进行 <slot> 替换,这个过程被
叫做分发
分发实际上就是将组件封装过程中不确定的内容,留存到组件调用时才进行定义
分发按照分发特性分成如下几种
1 默认分发 (定义的 slot 为通过 name 属性 指定名称)
+ 会将当前组件标签中未被 v-slot 指令描述的所有内容作为整体进行页面克隆,
并将克隆的结果分别填充到所有没有 name 属性的 slot 位置
2 具名分发 (在构建 slot 时通过 name 属性 定义当前插槽的名称)
+ 会将当前组件中被定义了 v-slot 指令的描述内容进行克隆,并将克隆的结果
填充到对应名称(name=名称)的 slot 位置
+ v-slot 指令被定义在template模板标签上,通过指令 : 参数的方式描述插槽的名称
+ v-slot 可以通过 # 关键字进行简写
+ 默认分发从分发功能上来说其实也是具名分发,默认分的slot,name默认值为default
slot 插槽标签内部可以填充标签或数据,这些数据被叫做分发默认值
-->
.btn{
display: inline-block;
padding: 10px 20px;
border: 1px solid #dedede;
cursor: pointer;
border-radius: 6px;
background-color: #409eff;
color: white;
}
.btn img{
height: 16px;
}
.btn:hover{
filter: opacity(0.8);
}
</style>
</head>
<body>
<div id="app">
<h4>按钮组件</h4>
<br>
<itany-btn>注册</itany-btn>
<itany-btn>登录</itany-btn>
<itany-btn>退出</itany-btn>
<itany-btn>
<i class="iconfont icon-edit"></i>
退出
</itany-btn>
<br><br>
<itany-btn>
<span>默认分发内容</span>
<!-- 具名分发 -->
<template v-slot:loading>
<img src="../../assets/img/loading.gif" alt="" srcset="">
</template>
</itany-btn>
<br><br>
<itany-btn>
<span>默认分发内容</span>
<template #loading>
<img src="../../assets/img/loading.gif" alt="" srcset="">
</template>
</itany-btn>
<br><br>
<itany-btn>
<template #default>
<span>默认分发内容</span>
</template>
<template #loading>
<img src="../../assets/img/loading.gif" alt="" srcset="">
</template>
</itany-btn>
<br><br>
<itany-btn></itany-btn>
<br><br>
<itany-btn name="name属性"></itany-btn>
<br><br>
<itany-btn name="name属性">
<span>默认插槽</span>
</itany-btn>
</div>
<script type="text/x-template" id="itanyBtn">
<!--
vue语法中分发的意思是:在组件页面结构定义时,存在部分不确定的页面结构或者取值时,
可通过特殊占位标签 <slot> 进行位置定义,当该组件被使用时,
通过组件标签中填充的页面内容进行 <slot> 替换,这个过程被
叫做分发
分发实际上就是将组件封装过程中不确定的内容,留存到组件调用时才进行定义
分发按照分发特性分成如下几种
1 默认分发 (定义的 slot 为通过 name 属性 指定名称)
+ 会将当前组件标签中未被 v-slot 指令描述的所有内容作为整体进行页面克隆,
并将克隆的结果分别填充到所有没有 name 属性的 slot 位置
2 具名分发 (在构建 slot 时通过 name 属性 定义当前插槽的名称)
+ 会将当前组件中被定义了 v-slot 指令的描述内容进行克隆,并将克隆的结果
填充到对应名称(name=名称)的 slot 位置
+ v-slot 指令被定义在template模板标签上,通过指令 : 参数的方式描述插槽的名称
+ v-slot 可以通过 # 关键字进行简写
+ 默认分发从分发功能上来说其实也是具名分发,默认分的slot,name默认值为default
slot 插槽标签内部可以填充标签或数据,这些数据被叫做分发默认值
-->
<div class="btn">
<slot name="loading">loading</slot>
|
<!-- <slot>默认数据</slot> -->
<slot>{{ name }}</slot>
</div>
</script>
<script type="module">
import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
createApp({
data(){
return {
}
}
})
.component("ItanyBtn",{
template:"#itanyBtn",
props:{
name:{
type:String,
default:"默认数据"
}
}
})
.mount("#app")
</script>
插槽的作用域分发
vue中所谓的作用域插槽,实际上就是实现子组件渲染时将一些特殊数据变量,
通过插槽关系回传到调用位置(父组件位置)进行使用
子组件调用时的内容区域可以通过vue的语法关系构建出两个 取值作用域
1、父组件作用域 : 子组件调用时内容区域的默认作用域 【 标签定义在那个容器,作用域就是那个容器 】
2、子组件回传数据作用域 : (实现规则就是属性绑定+数据拦截)
+ 属性绑定 在 slot 标签上以 v-bind 完成子组件数据绑定
+ 在子组件标签的内容区域,通过 v-slot="自定义变量" 进行拦截
自定义变量 以取值 {} 等方式记录所有对应 slot 上绑定的属性
<body>
<div id="app">
<h3>列表组件</h3>
<itany-list :list="users">
<template v-slot:default="obj">
<div>{{ msg }}</div>
<div>{{ obj }}</div>
<div>{{ obj.info }}</div>
<div>{{ obj.row.name }}</div>
</template>
</itany-list>
<hr>
<!--
如果分发只有一个,可以直接定义在组件标签上
如果分发为默认分发,可以省略参数名称
-->
<itany-list :list="users2" v-slot="obj">
{{ obj.row.username }}
</itany-list>
<hr>
<!-- v-slot回传的对象,在进行调用时,可以直接使用 ES6 结构语法 -->
<itany-list :list="users2" v-slot="{ row,$index }">
{{ $index }}:{{ row.username }}
<!-- 因为回传的 row 数据为引用数据,可以直接操作 -->
<input type="text" v-model="users2[$index].username">
<input type="text" v-model="row.username">
</itany-list>
</div>
<script type="text/x-template" id="list">
<slot name="empty" v-if="list.length==0">{{ emptyText }}</slot>
<ul>
<li v-for="(item,i) in list">
<slot v-bind:info="info" :row="item" :$index="i"></slot>
</li>
</ul>
</script>
<script src="../../assets/mock/mock.js"></script>
<script type="module">
import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
createApp({
data(){
return {
msg:"父组件测试数据",
users:Mock.mock({
"list|10-10":[
{
id:"@id",
name:"@cname"
}
]
}).list,
users2:Mock.mock({
"list|10-10":[
{
id:"@id",
username:"@cname"
}
]
}).list
}
}
})
.component("ItanyList",{
template:"#list",
data() {
return {
info:"子组件数据"
}
},
props:{
list:{
type:Array,
default(){
return []
}
},
emptyText:{
type:String,
default:"暂无数据"
}
}
})
.mount("#app")
</script>
组件ref用法
<!-- vue中ref属性被定义在子组件标签上时,同样具在$refs中具有记录功能,但取值不是DOM,是组件实例 -->
// 通过$refs可以直接访问组件对象,通过组件对象可以直接调用组件方法
例:模态窗组件创建
<style>
body{
padding-bottom: 800px;
}
.dialog{
position: fixed;
top:0px;
bottom: 0px;
left: 0px;
right: 0px;
/* width: 100%;
height: 100%; */
background-color: rgba(51, 51, 51, 0.6);
}
.dialog-box{
position: absolute;
top: 10%;
left: 50%;
transform: translate(-50%,0px);
background-color: white;
width: 400px;
min-height: 400px;
box-shadow: 0px 0px 8px #dedede;
}
</style>
</head>
<body>
<div id="app">
<h4>模态窗组件</h4>
<ul>
<li v-for="(u, i) in users" :key="u.id">
{{ u.name }}
<input type="button" value="修改" @click="showEditDialog(u)">
</li>
</ul>
<!-- vue中ref属性被定义在子组件标签上时,同样具在$refs中具有记录功能,但取值不是DOM,是组件实例 -->
<itany-dialog v-model:flag="dialogFlag" ref="editUser">
<div>
<label>ID:</label>
<input type="text" readonly :value="tempUser.id">
</div>
<div>
<label>name:</label>
<input type="text" v-model="tempUser.name">
</div>
<input type="button" value="关闭" @click="dialogFlag=false">
<input type="button" value="修改" @click="editUser()">
</itany-dialog>
</div>
<script type="text/x-template" id="dialog">
<teleport to="body" >
<div class="dialog" v-if="flag" @click="$emit('update:flag',false)">
<div class="dialog-box" @click.stop>
<slot></slot>
</div>
</div>
</teleport>
</script>
<script src="../../assets/mock/mock.js"></script>
<script type="module">
import { createApp } from "../../assets/vue/3.0/vue.esm-browser.js";
createApp({
data(){
return {
dialogFlag:false,
users:Mock.mock({
"list|10-10":[
{
id:"@id",
name:"@cname"
}
]
}).list,
tempUser:{}
}
},
methods: {
showEditDialog(u){
// this.dialogFlag = true;
console.log(this.$refs.editUser);
// 通过$refs可以直接访问组件对象,通过组件对象可以直接调用组件方法
this.$refs.editUser.open();
this.tempUser = u;
},
editUser(){
console.log("被修改的数据:",this.tempUser);
this.dialogFlag = false;
}
},
})
.component("ItanyDialog",{
template:"#dialog",
emits:["update:flag"],
props:{
flag:{
type:Boolean,
default:false
}
},
methods:{
open(){
console.log("模态窗组件的自定义方法");
this.$emit("update:flag",true)
}
}
})
.mount("#app")
</script>