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
只用于一个根元素的动画监控
用于多个根元素的动画分别监控 (必须为所有内部的元素提供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>
- <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动画名称
- .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">
-
- <div class="btn">
- <slot name="loading">loadingslot>
- |
-
- <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>
-
- <itany-list :list="users2" v-slot="{ row,$index }">
- {{ $index }}:{{ row.username }}
-
- <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>
// 通过$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>
-
- <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>