【vue】 6.0 动态组件、slot插槽、单个元素动画
2021-05-31 本文已影响0人
bobokaka
插槽和具名插槽
比如说同一个组件如下代码:
const app = Vue.createApp({
template: `
<myform/>
<myform/>
`
});
app.component('myform', {
methods:{
handleClick(){
alert(123)
},
template: `
<div>
<div @click="handleClick">提交</div>
</div>
`
});
两个组件,同样是点击事件,但是第一个想div快点击,第二个是button点击,怎么办?
这时候就用到插槽(动态组件),直接使用slot,但是slot是无法绑定事件的。
const app = Vue.createApp({
template: `
<myform>
<div>提交</div>
</myform>
<myform>
<button>提交</div>
</myform>
`
});
app.component('myform', {
methods:{
handleClick(){
alert(123)
},
template: `
<div>
<input/>
<slot></slot>
</div>
`
});
绑定事件可以如下编写:
const app = Vue.createApp({
template: `
<myform>
<div>提交</div>
</myform>
<myform>
<button>提交</div>
</myform>
`
});
app.component('myform', {
methods:{
handleClick(){
alert(123)
},
template: `
<div>
<input/>
<span @click="handleClick">
<slot></slot>
</span>
</div>
`
});
父模版里调用的数据属性,使用的都是父模版里的数据
子模版里调用的数据属性,使用的都是子模版里的数据
slot也可以设定默认值,当没有模块传入时显示默认模块。
const app = Vue.createApp({
template: `
<myform>
<div>提交</div>
</myform>
<myform>
<button>提交</div>
</myform>
<myform>
</myform>
`
});
app.component('myform', {
methods:{
handleClick(){
alert(123)
},
template: `
<div>
<input/>
<slot>default value</slot>
</div>
`
});
当我们想更自由的处理插槽的时候,可以如下编写代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>lesson 20</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
</body>
<script>
// slot 插槽
// slot 中使用的数据,作用域的问题
// 父模版里调用的数据属性,使用的都是父模版里的数据
// 子模版里调用的数据属性,使用的都是子模版里的数据
// 具名插槽
const app = Vue.createApp({
template: `
<layout>
<template v-slot:header>
<div>header</div>
</template>
<template v-slot:footer>
<div>footer</div>
</template>
</layout>
`
});
app.component('layout', {
template: `
<div>
<slot name="header"></slot>
<div>content</div>
<slot name="footer"></slot>
</div>
`
});
const vm = app.mount('#root');
</script>
</html>
动态组件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style type="text/css">
*{
margin: 0px;
padding: 0px;
}
html,body{
width: 100%;
height: 100%;
}
footer ul {
display: flex;
position: fixed;
left: 0px;
bottom: 0px;
width: 100%;
height: 40px;
}
footer ul li {
flex: 1;
text-align: center;
list-style: none;
height: 40px;
line-height: 40px;
background: gray;
}
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: translateX(100px);
opacity: 0;
}
100% {
transform: translateX(0px);
opacity: 1;
}
}
</style>
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
<div id="box">
<keep-alive>
<component :is="who"></component>
</keep-alive>
<footer>
<ul>
<li><a @click="who='home'">首页</a></li>
<li><a @click="who='list'" >列表页</a></li>
<li><a @click="who='shopcar'">购物车页面</a></li>
</ul>
</footer>
</div>
<script type="text/javascript">
//babel-loader ES6=>ES5
var home= {
template:`<div>
home
<input type="text"/>
</div>`
}
var list= {
template:`<div>
list
</div>`
}
var shopcar= {
template:`<div>
shopcar
</div>`
}
var vm = new Vue({
el:"#box",
data:{
// isHomeShow:true,
// isListShow:false,
// isShopcarShow:false
who:"home"
},
components:{
home,
list,
shopcar
}
})
</script>
</body>
</html>
slot(插槽)
a、b就是具名插槽,另一个333就是“单个slot”
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
<div id="box">
<hello>
<ul slot="a">
<li>111</li>
<li>111</li>
<li>111</li>
<li>111</li>
</ul>
<ul slot="b">
<li>222</li>
<li>222</li>
<li>222</li>
<li>222</li>
</ul>
<ul >
<li>333</li>
<li>333</li>
<li>333</li>
<li>333</li>
</ul>
</hello>
<!-- <swiper>
</swiper> -->
</div>
<script type="text/javascript">
var hello = {
template:`<div>
<slot name="b"></slot>
hello
<slot name="a"></slot>
<slot></slot>
</div>`
}
new Vue({
el:"#box",
data:{
},
components:{
hello
}
})
</script>
</body>
</html>
单个元素的动画
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
<div id="box">
<navbar>
<button @click="isShow = !isShow">show/hide</button>
</navbar>
<sidebar v-show="isShow"></sidebar>
<swipe>
<li>444444</li>
<li>555555</li>
<li>666666</li>
</swipe>
</div>
<script type="text/javascript">
//子组件
Vue.component("navbar",{
template:`<div>
navbar--<slot></slot>
</div>`
})
Vue.component("sidebar",{
template:`<div>
sidebar
<ul>
<li>1111</li>
<li>1111</li>
<li>1111</li>
<li>1111</li>
<li>1111</li>
<li>1111</li>
<li>1111</li>
</ul>
</div>`
})
Vue.component("swipe",{
template:`<div>
<ul>
<slot></slot>
</ul>
</div>`
})
var vm = new Vue({
el:"#box",
data:{
isShow:false
}
})
</script>
</body>
</html>
transition动画过渡效果
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style>
.kerwinfade-enter-active, .kerwinfade-leave-active {
transition: all 1.5s;
}
.kerwinfade-enter, .kerwinfade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
transform: translateX(100px);
}
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
opacity: 0;
transform: translateX(100px);
}
100% {
opacity: 1;
transform: translateX(0px);
}
}
</style>
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
<!-- <h1 class="animated heartBeat infinite ">1111111111111</h1> -->
<div id="box">
<button @click="isShow= !isShow">click</button>
<transition name="kerwinfade">
<p v-show="isShow">11111111111111111</p>
</transition>
<transition name="bounce">
<p v-show="isShow">2222222222222</p>
</transition>
<transition enter-active-class="animated bounceInRight" leave-active-class="animated bounceOutRight">
<p v-show="isShow">33333333333333333</p>
</transition>
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
isShow:true
}
})
//obox1.addEventListern("transitionEnd")
//obox2.addEventListern("animationEnd")
</script>
</body>
</html>
以上手写的也有好的框架可以直接使用
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style>
.kerwin-enter-active, .kerwin-leave-active {
transition: all .5s
}
.kerwin-enter, .kerwin-leave-to /* .fade-leave-active in below version 2.1.8 */ {
opacity: 0;
transform: translateX(100px);
}
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0%{
transform: translateX(100px);
opacity: 0;
}
100%{
transform: translateX(0px);
opacity: 1;
}
}
</style>
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
<!-- <div class="animated hinge infinite">1111111111111</div> -->
<div id="box">
<button @click="isShow= !isShow">click</button>
<transition name="bounce" appear>
<p v-show="isShow">11111111111</p>
</transition>
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
isShow:true
}
})
</script>
</body>
</html>
多个元素的组件动画
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style>
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: translateX(100px);
opacity: 0;
}
100% {
transform: translateX(0px);
opacity: 1;
}
}
</style>
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
<!-- <div class="animated hinge infinite">1111111111111</div> -->
<div id="box">
<button @click="isShow= !isShow">click</button>
<transition name="bounce" mode="out-in">
<div v-if="isShow" key="1">111111</div>
<div v-else key="2">222222</div>
</transition>
</div>
<script>
var vm = new Vue({
el:"#box",
data:{
isShow:true
}
})
// {
// tag:"div",
// text:"111111"
// }
// {
// tag:"p",
// text:"222222"
// }
/* Vue 为了减少对于dom 的操作
(1) key 目的:为了重用
key值相同, 就重用
key值不同,就不重用
(2) v-if v-else 如果标签相同,就重用,如果标签不同, 就不重用
*/
</script>
</body>
</html>
transition支持两个属性name和mode,其中mode只支持2个值:in-out 、out-in
多个组件过渡
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style type="text/css">
*{
margin: 0px;
padding: 0px;
}
html,body{
width: 100%;
height: 100%;
overflow-x: hidden;
}
footer ul {
display: flex;
position: fixed;
left: 0px;
bottom: 0px;
width: 100%;
height: 40px;
}
footer ul li {
flex: 1;
text-align: center;
list-style: none;
height: 40px;
line-height: 40px;
background: gray;
}
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: translateX(100px);
opacity: 0;
}
100% {
transform: translateX(0px);
opacity: 1;
}
}
</style>
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
<div id="box">
<keep-alive>
<transition name="bounce" mode="out-in">
<component :is="who"></component>
</transition>
</keep-alive>
<footer>
<ul>
<li><a @click="who='home'">首页</a></li>
<li><a @click="who='list'" >列表页</a></li>
<li><a @click="who='shopcar'">购物车页面</a></li>
</ul>
</footer>
</div>
<script type="text/javascript">
//babel-loader ES6=>ES5
var home= {
template:`<div>
home
<input type="text"/>
</div>`
}
var list= {
template:`<div>
list
</div>`
}
var shopcar= {
template:`<div>
shopcar
</div>`
}
var vm = new Vue({
el:"#box",
data:{
// isHomeShow:true,
// isListShow:false,
// isShopcarShow:false
who:"home"
},
components:{
home,
list,
shopcar
}
})
</script>
</body>
</html>
多个列表过渡
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<script type="text/javascript" src="lib/vue.js"></script>
<style>
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: translateX(100px);
opacity: 0;
}
100% {
transform: translateX(0px);
opacity: 1;
}
}
</style>
</head>
<body>
<div id="box">
<input type="text" v-model="mytext" />
<button @click="handleClick()">add</button>
<!-- <ul> -->
<transition-group tag="ul" name="bounce">
<li v-for="item,index in datalist" :key="item">
{{item}}--<button @click="handleDelClick(index)">del</button>
</li>
</transition-group>
<!-- </ul> -->
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#box",
data: {
mytext0: 111111,
mytext: 111111,
datalist: []
},
methods: {
handleClick: function() {
this.datalist.push(this.mytext);
this.mytext += this.mytext0
},
handleDelClick(index) {
console.log("del-click", index)
this.datalist.splice(index, 1); //删除
}
}
})
// 新老虚拟dom对比的 时候 会 使用 diff 算法。
//
//
//
// li -1111- 1111
// li -2222- 2222
// li- 3333- 3333
//
//
// li -1111- 1111
// li -33333- 3333
</script>
</body>
</html>
可复用过渡
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style>
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: translateX(-100%);
opacity: 0;
}
100% {
transform: translateX(0px);
opacity: 1;
}
}
</style>
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
<div id="box">
<navbar @myevent="control"></navbar>
<sidebar v-show="isShow"></sidebar>
</div>
<script type="text/javascript">
//子组件
Vue.component("navbar",{
template:`<div>
navbar--<button @click="handleClick">show/hide</button>
</div>`,
methods:{
handleClick(){
this.$emit("myevent");
}
}
})
Vue.component("sidebar",{
template:`
<transition name="bounce">
<div style="background:black;color:white;width:300px;">
sidebar
<ul>
<li>1111</li>
<li>1111</li>
<li>1111</li>
<li>1111</li>
<li>1111</li>
<li>1111</li>
<li>1111</li>
</ul>
</div>
</transition>
`
})
var vm = new Vue({
el:"#box",
data:{
isShow:false
},
methods:{
control(){
this.isShow = !this.isShow;
}
}
})
</script>
</body>
</html>
案例2:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>lesson 23</title>
<style>
/* 动画
@keyframes leftToRight {
0% {
transform: translateX(-100px);
}
50% {
transform: translateX(-50px);
}
0% {
transform: translateX(0px);
}
}
.animation {
animation: leftToRight 3s;
} */
/* 过渡
.transition {
transition: 3s background-color ease;
}
.blue {
background: blue;
}
.green {
background: green;
} */
.transition {
transition: 3s background-color ease;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
styleObj: {
background: 'blue'
}
}
},
methods: {
handleClick() {
if(this.styleObj.background === 'blue') {
this.styleObj.background = 'green';
}else {
this.styleObj.background = 'blue'
}
}
},
template: `
<div>
<div class="transition" :style="styleObj">hello world</div>
<button @click="handleClick">切换</button>
</div>
`
});
const vm = app.mount('#root');
</script>
</html>
单元素、单组件的出场入场,vue提供transition 标签。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>lesson 24</title>
<style>
@keyframes shake {
0% {
transform: translateX(-100px)
}
50% {
transform: translateX(-50px)
}
100% {
transform: translateX(50px)
}
}
.hello-leave-active {
animation: shake 3s;
}
.hello-enter-active {
animation: shake 3s;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
</body>
<script>
// 单元素,单组件的入场出场动画
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
}
},
template: `
<div>
<transition name="hello">
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">切换</button>
</div>
`
});
const vm = app.mount('#root');
</script>
</html>