Vue基础入门(中)

组件的定义

组件具备复用性 注意:全局组件,只要定义了,处处可以使用,性能不高,但是使用起来简单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lesson 14</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>
    const app = Vue.createApp({
        template:`
        <div><count-parent/></div>
        <div><count/></div>
        <div><count/></div>
        `
    });

    app.component('count-parent',{
        template:`<count/>`
    })

    app.component('count',{
        data(){
            return{
                count:1
            }
        },
        template:`<div @click="count+=1">{
   
   {count}}</div>`
    })
    const vm=app.mount('#root');
</script>

</html>

 与其对应的还有局部组件

const counter={
        data(){
            return{
                counter:1
            }
        },
        template:`
            <div @click="counter+=1">{
   
   {counter}}</div>
        `
    }
    const app = Vue.createApp({
        components:{'counter':counter},
        template:`
            <div><counter/></div>
        `
    });

    const vm=app.mount('#root');

解释:单引号'counter'代表组件名字,也可随意命名,但是为了见名其意,建议使用变量名(es6语法中在key和value一样时可以只写counter即可) 

通常我们会这样写,代码如下

const Counter={
        data(){
            return{
                counter:1
            }
        },
        template:`
            <div @click="counter+=1">{
   
   {counter}}</div>
        `
    }

    const HelloWorld={
        template:`<div>hello world</div>`
    }
    const app = Vue.createApp({
        components:{
            //counter:Counter,
            //'hello-world':HelloWorld
            Counter,
            HelloWorld
        },
        template:`
            <div>
                <hello-world/>
                <counter/>
            </div>
        `
    });

    const vm=app.mount('#root');

 说明:局部组件定义了,要注册之后才能使用,性能比较高,但是使用起来麻烦,建议大写字母开头,驼峰命名法(注意:局部组件使用时,要做一个名字和组件间的映射对象,你不写映射,Vue底层也会自动尝试帮你做映射

静态动态传参区别 

子组件展示的内容不是固定的,而是父组件在调用子组件的时候给它传递动态的内容(注意:想要内容123是数字型,我们给他赋予动态传参v-bind:content,而content仅仅只是静态传参

const app = Vue.createApp({
        data(){
            return {
                num:123
            }
        },
        template:`
            <div>
                <test :content="num"/>
            </div>
        `
    });

    app.component('test',{
        props:['content'],
        template:`<div>{
   
   {typeof content}}<div>`
    });
    const vm=app.mount('#root');

const app = Vue.createApp({
        data(){
            return {
                num:()=>{
                    alert(123);
                }
            }
        },
        template:`
            <div>
                <test :content="num"/>
            </div>
        `
    });
//    String,Boolean,Array,Object,Function
    app.component('test',{
        props:{'content':Function},
        methods:{
            handleClick(){
                alert(456);
                this.content();
            }
        },
        template:`<div @click="this.handleClick">{
   
   {typeof content}}<div>`
    });
    const vm=app.mount('#root');

 

 const app = Vue.createApp({
        data(){
            return {
                num:123
            }
        },
        template:`
            <div>
                <test/>
            </div>
        `
    });

    // required 必须传值
    // default 默认值
    // validation 验证
    app.component('test',{
        props:{
            content:{
                type:Number,
                validation:function(value){
                    return value<1000;
                },
                default:function(){
                    return 456;
                }
            }
        },
        
        template:`<div>{
   
   {content}}</div>`
    });
    const vm=app.mount('#root');

 当遇到子组件需要传递很多参数的时候,可以考虑使用精简的语法v-bind="params"

// v-bind="params"等价于
    // :content="params.content" :a="params.a" :b="params.b" :c="params.c"
    const app = Vue.createApp({
        data() {
            return {
                params:{
                    content: 1234,
                    a: 123,
                    b: 456,
                    c: 789
                }
            }
        },
        template: `
            <div>
                <test :content="params.content" :a="params.a" :b="params.b" :c="params.c"/>
            </div>
        `
    });

    app.component('test', {
        props: ['content', 'a', 'b', 'c'],
        template: `<div>{
   
   {content}}-{
   
   {a}}-{
   
   {b}}-{
   
   {c}}</div>`
    });
    const vm = app.mount('#root');

特殊语法:属性传的时候,使用content-abc这种命名,接的时候,使用contentAbc命名

const app = Vue.createApp({
        data() {
            return {
                content:123
            }
        },
        template: `
            <div>
                <test :content-abc="content"/>
            </div>
        `
    });

    app.component('test', {
        props: ['contentAbc'],
        template: `<div>{
   
   {contentAbc}}</div>`
    });
    const vm = app.mount('#root');

单项数据流:子组件可以使用父组件传递过来的数据,但是不能修改(想要修改的话得使用自己的属性赋值)

const app = Vue.createApp({
        data() {
            return {
                num:1
            }
        },
        template: `
            <div>
                <counter :count="num"/>
            </div>
        `
    });

    app.component('counter', {
        props: ['count'],
        data(){
            return{
                myCount:this.count
            }
        },
        template: `<div @click="myCount+=1">{
   
   {myCount}}</div>`
    });
    const vm = app.mount('#root');

Non-props属性

const app = Vue.createApp({
        template: `
            <div>
                <counter msg="hello"/>
            </div>
        `
    });

    app.component('counter', {
        template: `
            <div>Count</div>
        `
    });
    const vm = app.mount('#root');

 加了inheritAttrs属性设置为false就没有其msg属性了

app.component('counter', {
        inheritAttrs:false,
        template: `
            <div>Count</div>
        `
    });

$attrs作用(把父组件传递过来的所有属性都放到该标签里)

const app = Vue.createApp({
        template: `
            <div>
                <counter msg="hello" msg1="hello1"/>
            </div>
        `
    });

    app.component('counter', {
        mounted(){
            console.log(this.attrs.msg);
        },
        template: `
            <div v-bind:msg="$attrs.msg">Count</div>
            <div v-bind="$attrs">Count</div>
            <div :msg1="$attrs.msg1">Count</div>
        `
    });
    const vm = app.mount('#root');

 

触发外面事件 this.$emit()

const app = Vue.createApp({
        data(){
            return{
                count:1
            }
        },
        methods:{
            handleAddOne(){
                return this.count+=1;
            }
        },
        template: `
            <div>
                <counter :count="count" @add-one="handleAddOne"/>
            </div>
        `
    });

    app.component('counter', {
        props:['count'],
        emits:['addOne'],
        methods:{
            handleClick(){
                this.$emit('addOne');
            }
        },
        template: `
            <div @click="handleClick">{
   
   {count}}</div>
        `
    });
    const vm = app.mount('#root');

emits验证是否可以往外传不会报错只会警告 

const app = Vue.createApp({
        data(){
            return{
                count:1
            }
        },
        methods:{
            handleAdd(count){
                this.count=count;
            }
        },
        template: `
            <div>
                <counter :count="count" @add="handleAdd"/>
            </div>
        `
    });

    app.component('counter', {
        props:['count'],
        emits:{
            add:(count)=>{
                if(count>10){
                    return true;
                }
                return false;
            }
        },
        methods:{
            handleClick(){
                this.$emit('add',this.count+3);
            }
        },
        template: `
            <div @click="handleClick">{
   
   {count}}</div>
        `
    });
    const vm = app.mount('#root');

高级东西(了解一下)

const app = Vue.createApp({
        data(){
            return{
                count:1
            }
        },
        template: `
            <div>
                <counter v-model="count"/>
            </div>
        `
    });

    app.component('counter', {
        props:['modelValue'],
        methods:{
            handleClick(){
                this.$emit('update:modelValue',this.modelValue+3)
            }
        },
        template: `
            <div @click="handleClick">{
   
   {modelValue}}</div>
        `
    });
    const vm = app.mount('#root');
const app = Vue.createApp({
        data(){
            return{
                count:1
            }
        },
        template: `
            <div>
                <counter v-model:app="count"/>
            </div>
        `
    });

    app.component('counter', {
        props:['app'],
        methods:{
            handleClick(){
                this.$emit('update:app',this.app+3)
            }
        },
        template: `
            <div @click="handleClick">{
   
   {app}}</div>
        `
    });
    const vm = app.mount('#root');

选修课(较难)

拼接字符串且转换为大写形式(自定义修饰符:modelModifiers)

const app = Vue.createApp({
        data() {
            return {
                count: 'a'
            }
        },
        template: `
            <counter v-model.uppercase="count"/>
        `
    });

    app.component('counter', {
        props: {
            'modelValue': String,
            'modelModifiers': {
                default: () => ({})
            }
        },
        methods: {
            handleClick() {
                let newValue = this.modelValue + 'b';
                if (this.modelModifiers.uppercase) {
                    newValue = newValue.toUpperCase();
                }
                this.$emit('update:modelValue', newValue);
            }
        },
        template: `
            <div @click="handleClick">{
   
   {modelValue}}</div>
        `
    });
    const vm = app.mount('#root');

slot插槽

传递dom节点或者标签就可以使用插槽 

父模板里调用的数据属性,使用的都是父模板里的数据

子模板里调用的数据属性,使用的都是子模板里的数据

const app = Vue.createApp({
        data(){
            return{
                text:'提交'
            }
        },
        template: `
            <myform>
                <div>{
   
   {text}}</div>    
            </myform>
            <myform>
                <button>{
   
   {text}}</button>    
            </myform>
        `
    });

    app.component('myform', {
        methods:{
            handleClick(){
                alert(123);
            }
        },
        template: `
            <input/>
            <span @click="handleClick">
                <slot></slot>
            </span>
        `
    });
    const vm = app.mount('#root');

具名插槽(拆分插槽)

简写形式#header相当于v-slot:header

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:`
            <slot name="header"></slot>
            <div>content</div>
            <slot name="footer"></slot>
        `
    });

    const vm=app.mount('#root');

插槽高级语法

作用域插槽(写Vue插件常用)

const app=Vue.createApp({
        template:`
            // <list v-slot="slotProps">
            //     <div>{
   
   {slotProps.item}}</div>    
            // </list>
            <list v-slot="{item}">
                <div>{
   
   {item}}</div>    
            </list>
        `
    });

    app.component('list',{
        data(){
            return{
                list:[1,2,3]
            }
        },
        template:`
            <slot v-for="item in list" :item="item"/>
        `
    });

    const vm=app.mount('#root');

说明:首先父组件去调用list子组件,这一块<div>{ {slotProps.item}}</div>就是传递给子组件的slot,在子组件去循环内容的时候,去调用slot意思就是通过<div></div>这种形式去展示内容,但是,我在调用slot的时候把数据传给slot(把item这些数据传给slot)然而slot怎么接收呢?它通过v-slot=“slotProps”这样的一个数据对象(传递过来的所有内容都放在这个对象中),接收了之后,这就可以使用传递过来的item内容(当子组件渲染的内容要由父组件决定的时候

Vue动态组件 

 根据数据的变化,结合component这个标签,来随时动态切换组件的现实

const app = Vue.createApp({
        data() {
            return {
                currentItem: 'input-item'
            }
        },
        methods: {
            handleClick() {
                this.currentItem = this.currentItem === 'input-item' ? 'common-item' : 'input-item';
            }
        },
        template: `
            <keep-alive><component :is="currentItem"/></keep-alive>
            <button @click="handleClick">切换</button>
        `
    });

    app.component('input-item', {
        template: `
            <input/>
        `
    });

    app.component('common-item', {
        template: `
            <div>hello world</div>
        `
    });
    const vm = app.mount('#root');

Vue异步组件

是异步执行某些组件的逻辑,这叫异步组件

const app = Vue.createApp({
        template: `
            <common-item />
            <asyncComponent />
        `
    });
    app.component('common-item', {
        template: `
            <div>hello world</div>
        `
    });
    app.component('asyncComponent', Vue.defineAsyncComponent(() => {
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve({
                    template:`<div>this is an async component</div>`
                })
            },4000)
        });
    })
    );
    const vm = app.mount('#root');

v-once和ref 

v-once 让某个元素标签只渲染一次
ref 实际上是获取dom节点/组件引用的一个语法 


    const app = Vue.createApp({
        data(){
            return{
                count:1
            }
        },
        mounted(){
            this.$refs.common.sayHello();
        },
        template: `
            <div>
                <common-item ref="common"/>
            </div>
        `
    });

    app.component('common-item',{
        methods:{
            sayHello(){
                alert('hello');
            }
        },
        template:`<div>hello world</div>`
    })
    
    const vm = app.mount('#root');

 显示hello world之前弹出hello

provide/inject跨多级值的传递

const app = Vue.createApp({
        data(){
            return{
                count:1
            }
        },
        // provide:{
        //     count:1
        // },
        provide(){
            return{
                count:this.count,
            }
        },
        template: `
            <div>
                <child :count="count"/>
            </div>
        `
    });

    app.component('child',{
        template:`<child-child/>`
    })

    app.component('child-child',{
        inject:['count'],
        template:`<div>{
   
   {count}}</div>`
    })

    const vm = app.mount('#root');

 注意:count变化provide里面的东西不会跟着变化,只渲染一次

动画

transform:translateX 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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;
        }
    </style>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                animate: {
                    animation: true
                }
            }
        },
        methods: {
            handleClick() {
                this.animate.animation = !this.animate.animation;
            }
        },
        template: `
            <div :class="animate">hello world</div>
            <button @click="handleClick">切换</button>
        `
    });

    const vm = app.mount('#root');
</script>
</html>

过渡

transition 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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-color: blue;
        }

        .green{
            background-color: green;
        }
    </style>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                animate: {
                    transition:true,
                    blue:true,
                    green:false
                }
            }
        },
        methods: {
            handleClick() {
                if(this.animate.blue){
                    this.animate.blue=!this.animate.blue;
                    this.animate.green=!this.animate.green;
                }else{
                    this.animate.blue=!this.animate.blue;
                    this.animate.green=!this.animate.green;
                }
            }
        },
        template: `
            <div :class="animate">hello world</div>
            <button @click="handleClick">切换</button>
        `
    });

    const vm = app.mount('#root');
</script>
</html>

 也可以下面这样写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lesson 23</title>
    <style>
        .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 class="transition" :style="styleObj">hello world</div>
            <button @click="handleClick">切换</button>
        `
    });

    const vm = app.mount('#root');
</script>
</html>

单元素单组件的入场出场过渡动画 

过渡 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lesson 24</title>
    <style>
        .v-enter-from{
            opacity: 0;
        }
        .v-enter-active,.v-leave-active{
            transition: opacity 3s ease-out;
        }
        .v-enter-to{
            opacity: 1;
        }
        .v-leave-to{
            opacity: 0;
        }
    </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>
                    <div v-if="show">hello world</div>
                </transition>
                <button @click="handleClick">切换</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>
</html>

动画 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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);
            }
        }
        .v-enter-active,
        .v-leave-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>
                    <div v-if="show">hello world</div>
                </transition>
                <button @click="handleClick">切换</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>
</html>

如果我们给它命名的话<transition name="hello"></transition>,那么style里面的v-enter-from这些都需要换为hello-enter-from

引入第三方样式库

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link
        rel="stylesheet"
        href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
    />
    <title>lesson 24</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>
    // 单元素,单组件的出场入场动画
    // v-show隐藏还是会占用div的
    const app = Vue.createApp({
        data() {
            return {
                show: false
            }
        },
        methods: {
            handleClick() {
                this.show=!this.show;
            }
        },
        template: `
            <div>
                <transition
                    enter-active-class="animate__animated animate__flash"
                    leave-active-class="animate__animated animate__flash"
                >
                    <div v-show="show">hello world</div>
                </transition>
                <button @click="handleClick">切换</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>
</html>

过渡和动画相结合 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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);
            }
        }
        .v-enter-from{
            color: red;
        }
        .v-enter-active{
            animation: shake 3s;
            transition: color 3s ease-in;
        }
        /*动画从红变黑,再由黑变红*/
        .v-leave-active{
            animation: shake 3s;
            transition: color 3s ease-in;
            color: red;
        }
    </style>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>
    // 单元素,单组件的出场入场动画
    // v-show隐藏还是会占用div的
    const app = Vue.createApp({
        data() {
            return {
                show: false
            }
        },
        methods: {
            handleClick() {
                this.show=!this.show;
            }
        },
        template: `
            <div>
                <transition>
                    <div v-show="show">hello world</div>
                </transition>
                <button @click="handleClick">切换</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>
</html>

当动画和过渡时间不一致时,可以在<transition type="animation"></transition>标签中添加type属性,表示以动画时间为准,当不想以css中设置时间来响应,可以在<transition :duration="{enter:1000,leave:3000}"></transition>标签中添加duration属性

使用js来处理动画和过渡 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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);
            }
        }
        .v-enter-from{
            color: red;
        }
        .v-enter-active{
            animation: shake 10s;
            transition: color 3s ease-in;
        }
        .v-leave-active{
            animation: shake 10s;
            transition: color 3s ease-in;
            color: red;
        } */
    </style>
    <script src="https://unpkg.com/vue@next"></script>
</head>

<body>
    <div id="root"></div>
</body>
<script>
    // 单元素,单组件的出场入场动画
    // v-show隐藏还是会占用div的
    const app = Vue.createApp({
        data() {
            return {
                show: false
            }
        },
        methods: {
            handleClick() {
                this.show = !this.show;
            },
            handleBeforeEnter(el) {
                el.style.color = "red";
            },
            handleEnterActive(el, done) {
                const animation = setInterval(() => {
                    const color = el.style.color;
                    if (color === 'red') {
                        el.style.color = 'green';
                    } else {
                        el.style.color = 'red';
                    }
                }, 1000);
                setTimeout(() => {
                    clearInterval(animation);
                    done();
                }, 3000);
            },
            handleEnterEnd(){
                alert(123);
            }
        },
        template: `
            <div>
                <transition
                  :css="false"
                  @before-enter="handleBeforeEnter"
                  @enter="handleEnterActive"
                  @after-enter="handleEnterEnd"
                >
                    <div v-show="show">hello world</div>
                </transition>
                <button @click="handleClick">切换</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>

</html>

多个单元素标签切换先隐藏再出现

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lesson 25</title>
    <style>
        .v-enter-from,
        .v-leave-to{
            opacity: 0;
        }
        .v-enter-active,
        .v-leave-active{
            transition: opacity 1s ease-in;
        }
        .v-enter-to,
        .v-leave-from{
            opacity: 1;
        }
    </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 mode="out-in" appear>
                    <div v-if="show">hello world</div>
                    <div v-else="show">bye world</div>
                </transition>
                <button @click="handleClick">切换</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>

</html>

多个单元素组件切换先隐藏再出现一

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lesson 25</title>
    <style>
        .v-enter-from,
        .v-leave-to{
            opacity: 0;
        }
        .v-enter-active,
        .v-leave-active{
            transition: opacity 1s ease-in;
        }
        .v-enter-to,
        .v-leave-from{
            opacity: 1;
        }
    </style>
    <script src="https://unpkg.com/vue@next"></script>
</head>

<body>
    <div id="root"></div>
</body>
<script>
    // 多个单组件之间的切换
    const ComponentA={
        template: `<div>hello world</div>`
    }
    const ComponentB={
        template: `<div>bye world</div>`
    }
    const app = Vue.createApp({
        data() {
            return {
                show: false
            }
        },
        methods: {
            handleClick() {
                this.show = !this.show;
            },
            
        },
        components:{
            'component-a':ComponentA,
            'component-b':ComponentB,
        },
        template: `
            <div>
                <transition mode="out-in" appear>
                    <component-a v-if="show"/>
                    <component-b v-else="show"/>
                </transition>
                <button @click="handleClick">切换</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>

</html>

多个单元素组件切换先隐藏再出现二

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lesson 25</title>
    <style>
        .v-enter-from,
        .v-leave-to{
            opacity: 0;
        }
        .v-enter-active,
        .v-leave-active{
            transition: opacity 1s ease-in;
        }
        .v-enter-to,
        .v-leave-from{
            opacity: 1;
        }
    </style>
    <script src="https://unpkg.com/vue@next"></script>
</head>

<body>
    <div id="root"></div>
</body>
<script>
    // 多个单组件之间的切换
    const ComponentA={
        template: `<div>hello world</div>`
    }
    const ComponentB={
        template: `<div>bye world</div>`
    }
    const app = Vue.createApp({
        data() {
            return {
                component: 'component-a'
            }
        },
        methods: {
            handleClick() {
                if(this.component==='component-a'){
                    this.component='component-b';
                }else{
                    this.component='component-a';
                }
            },
            
        },
        components:{
            'component-a':ComponentA,
            'component-b':ComponentB,
        },
        template: `
            <div>
                <transition mode="out-in" appear>
                    <component :is="component"/>
                </transition>
                <button @click="handleClick">切换</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>

</html>

列表动画的实现 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lesson 26</title>
    <style>
        .v-enter-from{
            opacity: 0;
            transform: translateY(30px);
        }
        .v-enter-active{
            transition: all .5s ease-in;
        }
        .v-enter-to{
            opacity: 1;
            transform: translateY(0px);
        }
        .list-item{
            display: inline-block;
            margin-right: 10px;
        }
        .v-move{
            transition: all .5s ease-in;
        }
    </style>
    <script src="https://unpkg.com/vue@next"></script>
</head>

<body>
    <div id="root"></div>
</body>
<script>
    // 列表动画的实现
    const app = Vue.createApp({
        data() {
            return {
                list:[1,2,3]
            }
        },
        methods: {
            handleClick() {
                this.list.unshift(this.list.length+1);
            },
            
        },
        template: `
            <div>
                <transition-group>
                    <span class="list-item" v-for="item in list" :key="item">{
   
   {item}}</span>
                </transition-group>
                <button @click="handleClick">增加</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>

</html>

状态动画的实现 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lesson 26</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>

<body>
    <div id="root"></div>
</body>
<script>
    // 状态动画的实现
    const app = Vue.createApp({
        data() {
            return {
                number: 1,
                animateNumber: 1
            }
        },
        methods: {
            handleClick() {
                this.number = 10;
                if (this.animateNumber < this.number) {
                    const animation = setInterval(() => {
                        this.animateNumber += 1;
                        if (this.animateNumber === 10) {
                            clearInterval(animation);
                        }
                    }, 100);
                }
            },

        },
        template: `
            <div>
                <div>{
   
   {animateNumber}}</div>
                <button @click="handleClick">增加</button>
            </div> 
        `
    });

    const vm = app.mount('#root');
</script>

</html>

猜你喜欢

转载自blog.csdn.net/bubbleJessica/article/details/130298154
今日推荐