You辉编程_VUE3.0

一、vue(上)

1.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>vueStart</title>
</head>
<body>
    <div id="app"></div>
    <!-- 引入vue的库 -->
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        //创建vue应用
        const app = Vue.createApp({
            data(){
                return{
                    message:'hello vue'
                }
            },
            template:`<div>{{message}}</div>`
        });
        //挂载
        //vm就是vue的根组件
        const vm = app.mount('#app');
    </script>
</body>
</html>

2.先了解一点点 

<!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></title>
</head>
<body>
    <div id="app">先了解一点点</div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * vue 面向数据编程
        */
        const app = Vue.createApp({
            data(){
                return{
                    content: 1
                }
            },
            //挂载完成执行
            mounted(){
                setInterval(()=>{
                    this.content += 1;
                },1000)
            },
            template:'<div>{{content}}</div>'
        });

        
        app.mount('#app');
    </script>
</body>
</html>

3.基础操作 

<!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>基础操作</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        // Vue.createApp({
        //     data(){
        //         return{
        //             content:'hello'
        //         }
        //     },
        //     methods:{
        //         handleBtnClick(){
        //            this.content = this.content.split('').reverse().join('');
        //         }
        //     },
        //     template:`
        //     <div>
        //         {{content}}
        //         <button @click="handleBtnClick">反过来打印</button>
        //     </div>`
        // }).mount("#app");


        /**
         * 显示/隐藏
         *
        */
        Vue.createApp({
            data(){
                return{
                    show: true,
                }
            },
            methods:{
                handleBtnClick(){
                   this.show = false;
                //    this.show = !this.false;
                }
            },
            template:`
            <div>
                <span v-if="show">内容</span>
                <button @click="handleBtnClick">显示/隐藏</button>
            </div>`
        }).mount("#app");
    </script>
</body>
</html>

4. 循环和双向绑定

<!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>循环和双向绑定</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        Vue.createApp({
            data(){
                return{
                    inputVal:'',
                    list:[]
                }
            },
            methods:{
                hanleAddItem(){
                    this.list.push(this.inputVal);
                    this.inputVal = ''
                }
            },
            template:`
            <div>
                <input v-model="inputeVal" />
                <button @click="hanleAddItem">添加数据 </button>
                <ul>
                   <li v-for="item of list">{{item}}</li> 
                </ul>
            </div>`
        }).mount("#app");
    </script>
</body>
</html>

5.组件 

<!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>组件</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 数据双向绑定(同步更新) v-model
         * 数据与属性绑定 :title = 'valueName'
        */
        const app = Vue.createApp({
            data(){
                return{
                    inputVal:'',
                    list:[]
                }
            },
            methods:{
                hanleAddItem(){
                    this.list.push(this.inputVal);
                    this.inputVal = ''
                }
            },
            template:`
            <div>
                <input v-model="inputeVal" />
                <button @click="hanleAddItem" :title="inputVal">添加数据 </button>
                <ul>
                   <todo-item
                    v-for="(item,index) of list"
                    :content="item"
                    :index="index"
                    />
                </ul>
            </div>`
        })

        //注册组件(只有注册才能使用)
        app.component('todo-item',{
            props:['content','index'], //props用来接收父组件绑定的属性值
            template:`<li>{{content}}-{{index}}</li>`
        });
        /**
         * 组件之间可以通过绑定属性的方式传值
         * 接收值用props['srcName1','srcName2']
        */
        app.mount("#app");
    </script>
</body>
</html>

6.稍微扩展一点

<!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>扩展</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * vue其实是参考了mvvm
         * m-->model数据,v-->view视图,vm-->viewModel视图数据连接层
        */
        const app = Vue.createApp({
            data(){
                return{
                    message:'hello'
                }
            },
            template:`<div>{{message}}</div>`
        });
        //vm就是vue的根组件
        const vm = app.mount('#app');
        //获取根组件上的数据:vm.$data.
    </script>
</body>
</html>

7. 常用的生命周期函数

<!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>常用的生命周期函数</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 生命周期函数:在某一时刻会自动执行的函数
         * 生命周期函数有很多,常用的就下面四个,其他可到vue官网了了解
        */
        const app = Vue.createApp({
            data(){
                return{
                    message:'hello'
                }
            },
            //vue应用创建之前执行
            beforeCreate(){
                alert('beforeCreate');
            },
            //vue应用创建完成执行
            created(){
                alert('created');
            },
            //挂载完成之前执行
            beforeMounted(){
                alert('beforeMounted');
            },
            //挂载完成后执行
            mounted(){
                alert('mounted');
            },
            template:`<div>{{message}}</div>`
        });
        app.mount('#app');
    </script>
</body>
</html>
</html>

8.常用模板语法

<!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>常用模板语法</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 常用模板语法
         * 差值表达式:{{}}
         * 转义:v-html
         * 绑定属性: v-bing 或 : (绑定标题等)
         * v-noce:<div v-once>内容</div>-->div里的内容只使用一次,即使改变内容也改变不了
         * v-if: v-if="show":data里的show的状态
         * 事件绑定:v-on 或 @
         * 修饰符:prevent-->阻止默认行为:@click.prevent="handleClick";
         * 数据绑定会涉及到修饰符,先了解一下,后面还会提到,如
         * 数字类型:v-model.nunber=""
         * 失去焦点才触发数据的双向绑定:v-model.lazy=""
         * 输入框首位去空格:v-model.trim=""
        */
        const app = Vue.createApp({
            data(){
                return{
                    message:<strong>hello</strong>
                }
            },
            template:`<div v-html='message'></div>`
        });
        app.mount('#app');
    </script>
</body>
</html>
</html>

 9.数据.方法.计算属性和侦听器

<!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>数据.方法.计算属性和侦听器</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * data:数据
         * methods:方法
         * computed:计算属性
         * watcher:侦听器
         * this指向data里的数据
        */
        const app = Vue.createApp({
            data(){
                return{
                    message:'hello',
                    count: 2,
                    proce: 5,
                }
            },
            //watch监听数据有变化后打印处内容(异步)
            //异步处理,其他如computed等是不能的
            watch:{
                price(current, prev){ //current:接收的是当前的值,prev:接收的是之前的值
                    setTimeout(()=>{
                        console.log('数据变化2秒后的输出结果')
                    },2000)
                }
            },
            computed:{
                total(){
                    return this.count * this.price
                }
            },
            /**
             * 虽然方法也可以实现计算,但方法里的计算方法是会
             * 随着页面重新架加载重新执行,而计算属性里的函数
             * 则不会,会缓存数据,执行效率更高
            */
            methods:{
                getTotal(){
                    return this.count * this.price
                }
            },
            template:`<div>{{total}}</div>`
        });
        app.mount('#app');
    </script>
</body>
</html>
</html>

10.样式绑定语法

<!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>样式绑定语法</title>
    <style>
        .red{
            color:red;
        }
        .green{
            color:green;
        }
    </style>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return{
                    classString: 'red',
                    classObject:{ red: true, green: true },
                    classArray:['red', 'green'],
                    //行内样式绑定
                    styleString: 'color:blue',
                    //推荐
                    styleObject:{
                        color:'pink',
                        background:'yellow'
                    }
                }
            },
            template:`<div :style='styleObject'>
                hello
                <demo class='green' />
                </div>`
        });

        app.component('demo',{
            template:`<div :class='$attrs.class'>子组件的内容</div>`
        })
        app.mount('#app');
    </script>
</body>
</html>
</html>

11.条件渲染

<!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>条件渲染</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * v-if:直接去除
         * v-show:把display:none
         * 频繁改变状态用v-show
         * v-if可以结合v-else-id,v-else使用
        */
        const app = Vue.createApp({
            data(){
                return{
                    show:true,
                    conditionOne: true,
                    conditionTwo: true
                }
            },
            template:`
            <div v-if="show">hello</div>

            <div v-if="conditionOne">hello</div>
            <div v-else-if="conditionTwo">hello-1</div>
            <div v-else>world</div>

            <div v-show="show">world</div>
            `
        });
        app.mount('#app');
    </script>
</body>
</html>
</html>

12.列表渲染

<!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>列表渲染</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return{
                    listArray:['xiaoming','xiaohong','xiaojun'],
                    listObject:{
                        firstName:'xiaoming',
                        lastName:'xiaohong',
                        job:'student'
                    }
                }
            },
            methods:{
                handleAddBtnClick(){
                    //1.使用数组的方法
                    this.listArray.push('xiaoli');
                    //从末尾删除元素
                    //this.listArray.pop();
                    //从开头删除元素
                    //this.listArray.shift();
                    //从开头新增元素
                    //this.listArray.unshift('xiaoqiang');
                    //取反
                    //this.listArray.reverse();
                    //过滤
                    //this.listArray = ['xioayan','xiaohua'].filter(item=>item === 'xiaoyan')

                    //2.直接替换
                    //this.listArray = ['xiaoyan','xiaoyang']

                    //3.直接更新数组的内容
                    //this.listArray[0] = 'xiaoyan'

                    //添加对象的内容
                    this.listObject.age = 20,
                    this.listObject.sex = '男'
                }
            },
            /**
             * 在循环渲染的时候,为了减少性能消耗最好加一个:key="index"(唯一的key值)
            */
            template:`
            <div>
                <div v-for="(item,index) in listArray" :key="index">{{item}}-{{index}}</div>
                <div v-for="(value,key,index) in listObject">{{value}}-{{key}}-{{index}}</div>
                <button @click="handleAddBtnClick">新增</button>
            </div>
            `
        });
        app.mount('#app');
    </script>
</body>
</html>
</html>

13.事件绑定&修饰符

<!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>事件绑定&修饰符</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 1.事件绑定中常用的事件修饰符
         * @click.stop="handleEventName":阻止事件冒泡
         * @click.self="handleEventName":如果盒子内还有其他点击事件,只有点击自己才会执行
         * @click.prevent="handleEventName":阻止默认行为
         * @click.capture="handleEventName":设置为捕获状态(即从外到内)
         * @click.once="handleEventName":只执行一次
         * 2.事件绑定中的按键修饰符(指定是那一个按键)
         * @keydown.enter = "handleKeyDown":输入的时候只有按回车才会执行
         * tab,delete,shift等
         * 3.事件绑定中的鼠标修饰符
         * left,right,middle
         * @click.left="handleEventName"
         * 3.事件绑定中的精确(精确到按住哪一个键,点击时才会执行)修饰符
         * @click.alt="handleEventName"等
        */
        const app = Vue.createApp({
            data(){
                return{
                    count:0,
                }
            },
            methods:{
                handleBtnClick(num,event){
                    this.count += num;
                }
            },
            template:`
                <div>
                    {{count}}
                    <button @click='handleBtnClick(2,$event)'></button>
                </div>`
        });
        app.mount('#app');
    </script>
</body>
</html>
</html>

14.表单中双向绑定指令的使用

<!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>表单中双向绑定指令的使用</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 表单中的修饰符
         * v-model.lazy="message":输入框失去焦点时数据才同步
         * v-model.number="message":规定只能数据数字类型
         * v-model.trim="message":去除输入框前后的空格
        */
        const app = Vue.createApp({
            data(){
                return{
                    //message:'hello'
                    //message:[]
                    //message:''
                    message:'A'
                }
            },
            // template:`
            // <div>
            //     {{message}}
            //     <input v-model="message" />
            //     <textarea v-model="message" />
            // </div>`
            // template:`
            // <div>
            //     {{message}}
            //     xiaoming:<input type="checkbox" v-model="message" value="xiaoming" />
            //     xiaohong:<input type="checkbox" v-model="message" value="xiaohong" />
            //     xiaoyang:<input type="checkbox" v-model="message" value="xiaoyang" />
            // </div>`
            // template:`
            // <div>
            //     {{message}}
            //     xiaoming:<input type="radio" v-model="message" value="xiaoming" />
            //     xiaohong:<input type="radio" v-model="message" value="xiaohong" />
            //     xiaoyang:<input type="radio" v-model="message" value="xiaoyang" />
            // </div>`
            template:`
            <div>
                {{message}}
                <select v-model="message">
                    <option>A</option>
                    <option>B</option>
                    <option>C</option>
                </select>
            </div>`
        });
        app.mount('#app');
    </script>
</body>
</html>
</html>

15.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>vue基础综合案例</title>
</head>
<body>
    <div id="app">
        <h1>我的购物车</h1>
        <form @submit.prevent="insert">
            <input
             type="text"
             placeholder="商品名称"
             v-model="name"
            >
            <input
             type="text"
             placeholder="商品价格"
             v-model.number="price"
            >
            <button>添加商品</button>
        </form>
            <ul>
                <li v-for="(item,index) in list">
                    商品名称:{{item.name}}
                    商品价格:{{item.price}}
                    商品数量:
                    <button @click="sub(index)">-</button>
                    <span>{{item.count}}</span>
                    <button @click="add(index)">+</button>
                </li>
            </ul>
            <h1>总价:{{totalPrice}}</h1>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        Vue.createApp({
            data(){
                return {
                    // list:[
                    //     {
                    //         name:'香蕉',
                    //         price:0,
                    //         count:4
                    //     },
                    //     {
                    //         name:'苹果',
                    //         price:0,
                    //         count:4
                    //     }
                    // ]
                    list:[]
                }
            }, 
            //计算属性computed是单独的模块
            computed:{
                //总价计算需要一个函数才能完成
                totalPrice(){
                   let sum = 0;
                   this.list.forEach(v=>{
                       sum+= (v.price * v.count);
                   })
                   return sum;
                }
            },
            methods:{
                insert(){
                    this.list.push({
                        //输入框输入的内容
                        name:this.name,
                        price:this.price,
                        //默认值是1件商品
                        count:1,
                    })
                },
                sub(i){
                    /*通过索引把具体哪个商品传进来
                    *然后操作它自己的数量
                    */
                    this.list[i].count --;
                    if(this.list[i].count <1 &&
                     confirm('是否要删除该商品')){
                         //删除第i个删评并且只删除一个商品
                         this.list.splice(i,1);
                     }
                },
                add(i){
                    this.list[i].count ++;
                },
            }
        }).mount("#app")
    </script>
</body>
</html>

二、vue (中)

1.组件的定义

<!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>组件的定义</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            /**
             * 组件:简单来说组件就是页面的某个部分
             * 当一个页面比较复杂的时候,就需要把组件拆分出去
            */
            template: `
            <div>
                <hello />
                <world />
            </div>`,
        });

        /**
         * 定义全局组件:app.component("组件名",{})
         * 全局组件的使用:在使用组件的那个组件的模板里
         * 加上 <组件名 />即可
         * */
        app.component('hello',{
            template: `
                <div>hello</div>
            `,
        })
        app.component('world',{
            template: `
                <div>world</div>
           `,
        })
        const vm = app.mount("#app");
    </script>
</body>
</html>

2.全局组件

<!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>全局组件</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 组件具有复用性,并且组件中的数据是独立的
         * 在复用时互不影响
         * 全局组件:是通过app.component创建的
         * 全局组件定义之后,即使没有被使用,它也会占用app资源,
         * 但全局组件使用起来比较简单。
        */
        const app = Vue.createApp({
            template: `
            <div>
                <counter-parent />
            </div>`,
        });

        //定全局组件
        app.component('counter',{
            template: `
            <counter />
            `,
        })
        app.component('counter',{
            data(){
                return {
                    count:1,
                }
            },
            methods:{
                handleClick(){
                    this.count++;
                }
            },
            template: `
                <div @click="handleClick">{{count}}</div>
            `,
        })
        
        const vm = app.mount("#app");
    </script>
</body>
</html>

3. 局部组件

<!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>局部组件</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 定义局部组件 const 组件名 = {};组件名建议使用驼峰命名,
         * 只用在使用局部组件的组件里注册才能在模板里使用,
         * 注册:components:{counter:counter},
         * 布局组件性能高,但使用起来相对全局组件来说相对麻烦;
         * 为了性能,开发中一般使用局部组件
         * 局部组件之间的使用同理。
        */
        const Counter = {
            data(){
                return {
                    count:1,
                }
            },
            methods:{
                handleClick(){
                    this.count++;
                }
            },
            template: `
                <div @click="handleClick">{{count}}</div>
            `,
        }

        const newContent = {
            data(){
                return{
                    msg:"局部组件的内容,使用之前记得先在模板里注册。"
                }
            },
            template:`
            <p>{{msg}}</p>
            `
        }

        const app = Vue.createApp({
            //注册
            components:{ Counter, newContent },
            //使用
            template: `
            <div>
               <counter />
               <newContent /> 
            </div>`,
        });
        const vm = app.mount("#app");
    </script>
</body>
</html>

4.组件间的静态传值

<!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>组件间的传值(静态)</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            /**
             * 父组件调用子组件,父组件通过自定义属性
             * 向子组件传递值,子组将通过props,来接
             * 收父组件传递过来的值。
            */
            template: `
            <div>
                <content useContent="this  is useContent"></content>
            </div>`,
        });
        
        app.component("content",{
            /**
             * 要使用根组件中的useContent
             * 需要使用props
             * */
            props:["useContent"],
            template:`<div>{{useContent}}</div>`
        })
        const vm = app.mount("#app");
    </script>
</body>
</html>

5.组件间的动态传值

<!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>组件间的传值(动态)</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            /**
             * 如果父组件件要向子组件传参,就动态传
             * 参,即: :userData="123",没有冒号
             * 的是静态传参,即传一些字符类型的
            */
            data(){
                return{
                    num:123,
                    mes:"字符串",
                    fun:()=>{ alert("this is function") }
                }
            },
            template: `
            <div>
                <content :useData="num"></content>
                <newContent :useString="mes"></newContent>
                <func :useFun="fun"></func>
                <doType :useType="num"></doType>
            </div>`,
        });
        
        //接收Number
        app.component("content",{
            props:["useData"],
            template:`<div>{{useData}}</div>`
        })
        //接收String
        app.component("newContent",{
            /**
             * 注:如果父组件传过来的的值是字符串类型
             * 的数据,在props接收的时候需要以{}的形
             * 式接收,并且同时要声明其类型,这样就有
             * 了类型校验的作用,eg:String,boolean,
             * Array,Object,function,Symbol(占位符)等。
            */
            props:{ useString:String },
            template:`<div>{{useString}}</div>`
        })
        //接收function
        app.component("func",{
            props:{ useFun:Function },
            methods:{
                handleClick(){
                    alert("hello");
                    this.useFun();
                }
            },
            template:`<div @click="handleClick">{{useFun}}</div>`
        })
        //类型的校验:规定父组件传进来的必须是子组件规定的类型
        app.component("doType",{
            props:{
                useType:{
                    type:Number,
                    required: true
                }
            },
            template:`
                <div>{{useType}}</div>
            `
        })
        const vm = app.mount("#app");
    </script>
</body>
</html>

6.单项数据流

<!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>单项数据流</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 单向数据流
         * 父组件可以向子组件传递数据
         * 但这个数据不能在子组件修改,
         * 它是一个单边流的形式。
         * 如果想修改父组件中的数据,
         * 可以在子组件上重新定义数,
         * 把父组件的数据当作子组件
         * 的初始值即可。
        */
        const app = Vue.createApp({
            data(){
                return{
                    num:1,
                    /**
                     * 当需要传递多个数据时,
                     * 需要把数据封装到一个
                     * 对象中
                    */
                    params:{
                        num:123,
                        a:111,
                        b:222,
                        c:333
                    },
                    content:1024,
                }
            },
            template: `
            <div>
                <Counter :count="num"></Counter>
                <doType v-bind="params"></doType>
                <Content :content="content"></Content>
            </div>`,
        });
        app.component("Counter",{
            props:["count"],
            data(){
                return{
                    newCount:this.count,
                }
            },
            methods:{
                handleClick(){
                    this.newCount ++;
                }
            },
            template:`
                <div @click="handleClick">{{newCount}}</div>
            `
        })
        app.component("doType",{
            props:["num","a","b","c"],
            template:`
                <div>{{num}}-{{a}}-{{b}}-{{c}}</div>
            `
        })
        app.component("Content",{
            props:["content"],
            template:`
                <div>{{content}}</div>
            `
        })
        const vm = app.mount("#app");
    </script>
</body>
</html>

7.Non-Props属性

<!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>Non-Props属性</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * Non-Props属性
         * 在父组件给子组件传递数据的时候,
         * 子组件不用props接收也可以,vue
         * 底层会自动把父组件的dom附加到
         * 子组件模板中。在子组件使用时用
         * v-bind="$attrs"即可使用。
         * No-Props主要用于样式传递的场景。
        */
        const app = Vue.createApp({
            template: `
            <div>
                <content msg="hello" style="color:red"></content>
            </div>`,
        });
        app.component("content",{
            /**
             * 如果不想接收父组件的msg属性
             * 直接加上inheritAttrs:false
            */
            //inheriAttrs:false,
            /**
             * 当有多个节点时,需要用v-bind="$attrs"
             * 来指定谁需要父组件的样式
            */
            template:`
                <div :msg="$attrs.msg">Content</div>
                <div v-bind="$attrs">Content</div>
                <div>Content</div>
            `
        })
        const vm = app.mount("#app");
    </script>
</body>
</html>

8.父子组件如何通过事件进行通信

<!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>父子组件如何通过事件进行通信</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return{
                    num:1
                }
            },
            methods:{
                handleAdd(param){
                    this.num += param;
                }
            },
            /**
             * 用$emite记得在父组件的模板里用 @触发事件名 来监听
             * 子组件的事件
            */
            template: `
            <div>
                <content :count="num" @add="handleAdd"/>
            </div>`,
        });
        app.component("content",{
            props:["count"],
            methods:{
                handleClickAdd(){
                   /**
                    * 除了前面提到的把父组件的数据赋值给
                    * 子组件数据的方法,可以用$emit('eventName')
                    * 的方法,来操作父组件的数据
                   */
                  this.$emit("add",2);//向外触发一个事件
                }
            },
            template:`
                <div @click="handleClickAdd">{{count}}</div>
            `
        })
        const vm = app.mount("#app");
    </script>
</body>
</html>

9.插槽(slot)

<!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>插槽(slot)</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 插槽(slot):其实就是把调用的组件标签变为
         * 双标签往里面插内容,插入的内容就是插槽。
         * 插槽的使用:
         * 直接用<slot></slot>标签即可。
         * 插槽的作用:把自己的需求在父组件的插槽定义
         * 然后在子组件中使用,具有很好的灵活性。摆脱
         * 了属性属性形式的传值。多用于父组件给子组件
         * 传dom节点的场景,eg:div标签,以属性的方式
         * 传显然很麻烦。
        */
        const app = Vue.createApp({
            data(){
                return{
                    text:"提交"
                }
            },
            template: `
            <div>
                <myForm>
                    <div>{{text}}</div>
                </myForm>
                <myForm>
                    <button>{{text}}</button>
                </myForm>
            </div>`,
        });
        app.component("myForm",{
            methods:{
                handleClick(){
                    alert(333);
                }
            },
            /**
             * 注:slot标签是不可以绑定事件的,
             * 需要在slot外包裹一层进行事件的
             * 绑定
            */
            template:`
                <input type="text">
                <span @click="handleClick">
                <slot></slot>
                </span>
            `
        })
        const vm = app.mount("#app");
    </script>
</body>
</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>插槽(slot)-1</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return{
                    text:'提交'
                }
            },
            template: `
            <div>
                <myForm>
                    <div>{{text}}</div>
                </myForm>
                <myForm>
                    <button>{{text}}</button>
                </myForm>
            </div>`,
        });
        app.component("myForm",{
            methods:{
                handleClick(){
                    alert(333);
                }
            },
            
            template:`
                <input type="text">
                <span @click="handleClick">
                <slot></slot>
                </span>
            `
        })
        const vm = app.mount("#app");
    </script>
</body>
</html>

10.具名插槽

<!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>具名插槽</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 具名插槽:
         * 给插槽外层的template通过v-slot:插槽名的
         * 形式给插槽命名,命名后该插槽就是具名插槽。
         * eg:
         * <template  v-slot:header>
                <div>header</div>
            </template>
        * 可简写为:
           <template  #header>
                <div>header</div>
            </template>
        */
        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("#app");
    </script>
</body>
</html>

11.作用域插槽

<!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>作用域插槽</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 作用域插槽
        */
        const app = Vue.createApp({
            /**
             * 通过v-slot="slotProps"接收
            */
            template: `
                <list v-slot="slotProps">
                    <div>{{slotProps.item}}</div>    
                </list>
            `,
        });
        app.component("list",{
            data(){
                return{
                    list:[1,2,3,4,5]
                }
            },
            /* 通过:item="item"把item传给父组件 */
            template:`
                <div>
                    <slot v-for="item in list" :item="item"></slot>
                </div>
            `
        })
        const vm = app.mount("#app");
    </script>
</body>
</html>

12.动态组件

<!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>动态组件</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return{
                    currentItem:'input-item',
                }
            },
            methods:{
                handleClick(){
                    if(this.currentItem === 'input-item'){
                        this.currentItem = 'common-item';
                    }else{
                        this.currentItem = 'input-item';
                    }
                }
            },
            /**
             * 动态组件:根据数据的变化,结合component这个标签,来随时
             * 动态的切换组件的显示情况。
             * <component :is="currentItem" />
             * 缓存标签:<keep-alive></keep-alive>
            */
            template: `
                <keep-alive>
                    <component :is="currentItem" />
                </keep-alive>
                <button @click="handleClick">切换</button>
            `,
        });
        app.component("inputItem",{
            
            template:`
                <input />
            `
        })
        app.component("commonItem",{
            template:`
                <div>hello</div>
            `
        })
        const vm = app.mount("#app");
    </script>
</body>
</html>

13.异步组件

<!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>异步组件</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>

        
        const app = Vue.createApp({
            template: `
                <inputItem />
                <asyncCommonItem />
            `,
        });
        app.component("inputItem",{
            
            template:`
                <input />
            `
        })
        //异步组件的定义
        app.component("asyncCommonItem",Vue.defineAsyncComponent(()=>{
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    resolve({
                        template:`<div>这是异步组件的内容</div>`
                    })
                },3000)
            })
        }));
        const vm = app.mount("#app");
    </script>
</body>
</html>

14.语法补充

<!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>补充</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * v-once:某个元素标签只渲染一次。
         * ref:想获取哪个dom标签元素,就在哪个标签上加ref="name",
         * 通过this.$refs.name获取dom节点。
         * provide 和 inject结合使用,用于多层组件传值的情况,
         * 用provide定义数据,用inject来接收数据。
        */
        const app = Vue.createApp({
            data(){
                return{
                    num:1,
                    content:"hello",
                    count:1,
                }
            },
            //provide定义数据
            provide:{
                count:2,
            },
            //provide还可以使用data里的数据
            // provide(){
            //     count:this.count
            // },
            methods:{
                handleClickAdd(){
                    this.num ++;
                }
            },
            mounted(){
                console.log(this.$refs.domName);
            },
            template: `
                <div>
                    <div @click="handleClickAdd" v-once>{{num}}</div>
                    <div ref="domName">{{content}}</div>
                    
                </div>
                <div>
                     <Child :count="count" />
                </div>
            `,
        });
        app.component("Child",{
            template:`<childChild />`
        })
        app.component("childChild",{
            //inject接收数据
            inject:["count"],
            template:`<div>{{count}}</div>`
        })
       
        const vm = app.mount("#app");
    </script>
</body>
</html>

15.vue+css实现动画

<!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>vue实现css动画</title>
    <style>
        /* 动画 */
        @keyframes leftToRight {
            0%{
                transform:translateX(-100px);
            }
            50%{
                transform: translateX(-50px);
            }
            0%{
                transform: translateX(0px);
            }
        }
        .animation{
            animation:leftToRight 3s;
        }
    </style>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return{
                    animate:{
                        animation:false,
                    },

                }
            },
            methods:{
                handleClick(){
                    this.animate.animation = !this.animate.animation;
                }
            },
            template: `
                <div>
                     <div :class="animate">我是动画</div>
                     <button @click="handleClick">切换动画</button>
                </div>
                
            `,
        });
        
        const vm = app.mount("#app");
    </script>
</body>
</html>

16.vue+css实现过渡

<!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>vue实现css过渡</title>
    <style>
        .transition{
            transition:3s background-color ease;
        }
    </style>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data(){
                return{
                    styleObj:{
                        backgroundColor:'blue'
                    }
                }
            },
            methods:{
                handleClick(){
                    if(this.styleObj.backgroundColor === "blud"){
                        this.styleObj.backgroundColor = "blue";
                    }else{
                        this.styleObj.backgroundColor = "red";
                    }
                }
            },
            template: `
                <div>
                     <div class="transition" :style="styleObj">我是过渡</div>
                     <button @click="handleClick">点击过渡</button>
                </div>
                
            `,
        });
        
        const vm = app.mount("#app");
    </script>
</body>
</html>

17.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>transition标签实现单元组件的过渡</title>
    <style>
        /*动画*/
        @keyframes shake{
            0%{
                transform:translateX(-100px);
            }
            50%{
                transform:translateX(-50px);
            }
            100%{
                transform:translateX(50px);
            }
        }
        /*过渡的固定的入场写法*/
        .v-enter-from{
            opacity:0;
        }
        .v-enter-active{
            transition: opacity 3s ease-out;
        }
        .v-enter-to{
            opacity: 1;
        }

        /*过渡的固定的出场写法*/
        .v-leave-form{
            opacity: 1;
        }
        .v-leave-active{
            transition: opacity 3s ease-in;
        }
        .v-leave-to{
            opacity:0;
        }
    </style>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 单元素,单组件的入场出场动画
        */
        const app = Vue.createApp({
            data(){
                return{
                   show:false 
                }
            },
            methods:{
                handleClick(){
                   this.show = !this.show;
                }
            },
            /**
             * 入场和出场都封装在了<transition></transition>里了
            */
            template: `
                <div>
                    <transition>
                      <div v-if="show">hello</div>
                    </transition>
                     <button @click="handleClick">切换</button>
                </div>
            `,
        });
        
        const vm = app.mount("#app");
    </script>
</body>
</html>

18.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>transition标签实现单元组件的动画</title>
    <style>
        /*动画*/
        @keyframes shake {
            0% {
                transform: translateX(-100px);
            }

            50% {
                transform: translateX(-50px);
            }

            100% {
                transform: translateX(50px);
            }
        }


        .v-enter-active {
            animation: shake 2s;
        }


        .v-enter-active {
            animation: shake 2s;
        }
    </style>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    show: false
                }
            },
            methods: {
                handleClick() {
                    this.show = !this.show;
                }
            },
            /**
             * 补充:如果同时有过渡和动画,想要同步它们的执行时间
             * 就在transition标签上加 type="animation" 或 :duration="1000",
             * :duration="{ enter:1000,leave:3000 }"
             */
            template: `
                <div>
                    <transition>
                      <div v-if="show">hello</div>
                    </transition>
                     <button @click="handleClick">切换</button>
                </div>
            `,
        });

        const vm = app.mount("#app");
    </script>
</body>

</html>

19.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>transition标签动画库的使用</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * transition标签动画
         * 可以调用它的动画库,完成需要的
         * 动画。https://animate.style/
         */
        const app = Vue.createApp({
            data() {
                return {
                    show: false
                }
            },
            methods: {
                handleClick() {
                    this.show = !this.show;
                }
            },

            template: `
                <div>
                    <transition
                    enter-active-class="animate__animated animate__bounce"
                    leave-active-class="animate__animated animate__bounce"
                    >
                      <div v-if="show">hello</div>
                    </transition>
                     <button @click="handleClick">切换</button>
                </div>
            `,
        });

        const vm = app.mount("#app");
    </script>
</body>

</html>

20.transition标签+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>transition标签+js实现过渡和动画</title>

</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    show: false
                }
            },
            methods: {
                handleClick() {
                    this.show = !this.show;
                },
                handleBeforeEnter(el) {
                    el.style.color = 'red';
                },
                handleEnterActive(el, done) {
                    const animatiton = setInterval(() => {
                        const color = el.style.color;
                        if (color === "red") {
                            el.style.color = 'pink';
                        } else {
                            el.style.color = 'red';
                        }
                    }, 1000)
                    setTimeout(() => {
                        clearInterval(animatiton);
                        done();
                    }, 3000)
                },
                handleEnterEnd() {
                    alert("动画已经执行完");
                }
            },
            /**
             * 入场和出场都封装在了<transition></transition>里了
             * 如果需要js实现动画需要在transition标签上加@before-enter=""钩子
             * 出场动画:
             * @before-enter="handleBeforeEnter"
             * @enter="handleEnterActive"
             * @after-enter="handleEnterEnd"
             * 入场动画
             * @berfore-leave=""
             * @leave=""
             * @leave-after=""
             */
            template: `
                <div>
                    <transition
                    :css="false"
                    @before-enter="handleBeforeEnter"
                    @enter="handleEnterActive"
                    @after-enter="handleEnterEnd"
                    >
                      <div v-if="show">hello</div>
                    </transition>
                     <button @click="handleClick">切换</button>
                </div>
            `,
        });

        const vm = app.mount("#app");
    </script>
</body>

</html>

21.单元素间的动画切换

<!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>单元素间的动画切换</title>
    <style>
        /*入场*/
        .v-enter-from {
            opacity: 0;
        }

        /*入场的过程中*/
        .v-enter-active {
            transition: opacity 3s ease-in;
        }

        /*入场结束*/
        .v-enter-to {
            opacity: 1;
        }

        /*出场*/
        .v-leave-from {
            opacity: 1;
        }

        .v-leave-active {
            transition: opacity 3s ease-in;
        }

        .v-leave-to {
            opacity: 0;
        }
    </style>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    show: false
                }
            },
            methods: {
                handleClick() {
                    this.show = !this.show;
                }
            },

            template: `
                <div>
                    <transition mode="out-in" apppear>
                      <div v-if="show">hello</div>
                      <div v-else="show">world</div>
                    </transition>
                     <button @click="handleClick">切换</button>
                </div>
            `,
        });

        const vm = app.mount("#app");
    </script>
</body>

</html>

22.单组件间的动画切换

<!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>单组件间的动画切换</title>
    <style>
        /*入场*/
        .v-enter-from {
            opacity: 0;
        }

        /*入场的过程中*/
        .v-enter-active {
            transition: opacity 3s ease-in;
        }

        /*入场结束*/
        .v-enter-to {
            opacity: 1;
        }

        /*出场*/
        .v-leave-from {
            opacity: 1;
        }

        .v-leave-active {
            transition: opacity 3s ease-in;
        }

        .v-leave-to {
            opacity: 0;
        }
    </style>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const ComponentA = {
            template: `<div>hello</div>`
        }
        const ComponentB = {
            template: `<div>world</div>`
        }
        const app = Vue.createApp({
            data() {
                return {
                    show: false
                }
            },
            components: {
                ComponentA,
                ComponentB
            },
            methods: {
                handleClick() {
                    this.show = !this.show;
                }
            },

            template: `
                <div>
                    <transition mode="out-in" apppear>
                      <ComponentA v-if="show" />
                      <ComponentB v-else="show" />
                    </transition>
                     <button @click="handleClick">切换</button>
                </div>
            `,
        });

        const vm = app.mount("#app");
    </script>
</body>

</html>

23.列表动画

<!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>列表动画</title>
    <style>
        .v-enter-from {
            opacity: 0;
            transform: translateY(30px);
        }

        .v-enter-active {
            transition: all 2s ease-in;
        }

        .v-enter-to {
            opacity: 1;
            transform: translateY(0px);
        }

        .v-move {
            transition: all 2s ease-in
        }

        .list-item {
            display: inline-block;
            margin-left: 10px;
        }
    </style>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    list: [1, 2, 3]
                }
            },
            methods: {
                handleClick() {
                    this.list.unshift(this.list.length + 1);
                }
            },
            /**
             * 列表动画用<tansition-group></tansition-group>标签
             */
            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("#app");
    </script>
</body>

</html>

24.状态动画

<!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>状态动画</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <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);
                    }

                }
            },
            /**
             * 列表动画用<tansition-group></tansition-group>标签
             */
            template: `
                <div>
                    <div>{{animateNumber}}</div>
                    <button @click="handleClick">增加</button>
                </div>
            `,
        });

        const vm = app.mount("#app");
    </script>
</body>

</html>

三、vue(下)

1.局部Mixin

<!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>局部Mixin</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * Mixin:把某些内容混入到哪里去,
         * 组件 data, methods 优先级高于 mixin data, methods 优先级。
         * 生命周期函数:先执行mixin里的,再执行组件里的。
         * vue3建议尽量不要用mixin,因为它的可维护性不高,
         * 可用Composition API来代替,后面会提到。
         */

        //定义局部mixin
        const myMixin = {
            data() {
                return {
                    number: 2,
                    content: "Mixin"
                }
            },
            created() {
                console.log("mixin的函数");
            }
        }
        const app = Vue.createApp({
            data() {
                return {
                    number: 1,
                }
            },
            /**
             * 使用mixin即把mixin的内容混入
             */
            mixins: [myMixin],
            created() {
                console.log("组件")
            },
            methods: {
                handleClick() {
                    alert("hello");
                }
            },
            template: `
                <div>
                    <div>{{number}}</div>
                    <div>{{content}}</div>
                    <button @click="handleClick">增加</button>
                </div>
            `,
        });

        const vm = app.mount("#app");
    </script>
</body>

</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>局部Mixin-1</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 自定义属性会自动存入$options,所以使用。
         * 自定义属性时直接用$options即可。
         * 自定义属性:组件中的属性优先级高于 mixin 属性的优先级。
         */

        //定义局部mixin
        const myMixin = {
            //自定义属性
            number: 1,
        }
        const app = Vue.createApp({
            //自定义属性
            number: 2,
            mixins: [myMixin],
            template: `
                <div>
                    <div>{{this.$options.number}}</div>
                </div>
            `,
        });

        //修改属属性优先级
        appVue.config.optionMergeStrategies.number = (mixinVal, appVue) => {
            return mixinVal || appVue;
        };

        const vm = app.mount("#app");
    </script>
</body>

</html>

2.全局Mixin

<!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>全局Mixin</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    number: 1,
                }
            },
            created() {
                console.log("组件")
            },
            methods: {
                handleClick() {
                    alert("hello");
                }
            },
            template: `
                <div>
                    <div>{{number}}</div>
                    <div>{{content}}</div>
                    <button @click="handleClick">增加</button>
                </div>
            `,
        });

        /**
         * 定义全局Mixin
         * 全局Mixin不需要用mixins: [myMixin]使用,
         * vue底层会自动注入。但开发时,不推荐使用,
         * 全局Mixin可维护性不高。
         * */
        app.mixin({
            data() {
                return {
                    number: 2,
                    content: "Mixin"
                }
            },
            created() {
                console.log("mixin的函数");
            }
        })
        const vm = app.mount("#app");
    </script>
</body>

</html>

3.自定义指令

<!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>自定义指令</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 自定义指令:
         * 定义后,使用v-指令名即可使用自定义指令。
         * 注:局部自定义指令需要在组件注册才能使用
         */

        //定义局部指令
        // const directives = {
        //     focus: {
        //         mounted(el) {
        //             el.focus();
        //         }
        //     }
        // }
        const app = Vue.createApp({
            //局部指令的注册
            //directives,
            template: `
                <div>
                    <input v-focus />
                </div>
            `,
        });

        //定义全局指令
        app.directive("focus", {
            mounted(el) {
                el.focus();
            }
        })
        const vm = app.mount("#app");
    </script>
</body>

</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>自定义指令-1</title>
    <style>
        .header {
            position: absolute;
        }
    </style>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    top: 100,
                }
            },
            template: `
                <div v-pos="top" class="header">
                    <input />
                </div>
            `,
        });
        app.directive("pos", {
            mounted(el, binding) {
                el.style.top = binding.value + "px";
            },
            updated(el, binding) {
                el.style.top = binding.value + "px";
            }
        })
        const vm = app.mount("#app");
    </script>
</body>

</html>

4.Teleport传送门

<!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>Teleport传送门</title>
    <style>
        .area {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 200px;
            height: 300px;
            background: pink;
        }

        .mask {
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
            background: #000;
            opacity: 0.5;
        }
    </style>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * Teleport传送门其实就是一个标签
         * <teleport to="传送的地方"></teleport>
         * 传送到指定的地方,进行操作。
         */
        const app = Vue.createApp({
            data() {
                return {
                    show: false,
                }
            },
            methods: {
                handleBtnClick() {
                    this.show = !this.show;
                }
            },
            template: `
                <div class="area">
                    <button @click="handleBtnClick">按钮</button>
                    <teleport to="body">
                    <div class="mask" v-show="show"></div>
                    </teleport>
                </div>
            `,
        });

        const vm = app.mount("#app");
    </script>
</body>

</html>

5.render函数(底层)

<!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>render函数(底层)</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * template-->rander-->h-->生成虚拟DOM(js对象)-->真实的DOM-->展示在页面
         */
        const app = Vue.createApp({
            template: `
                <myTitle :level="1">
                    hello
                </myTitle>
            `,
        });
        app.component("myTitle", {
            props: ["level"],
            //render函数
            render() {
                const {
                    h
                } = Vue;
                /*h()返回是虚拟DOM*/
                return h("h" + this.level, {}, this.$slots.default())
            }
            // template: `
            //     <h1 v-if="level===1"><slot /></h1>
            //     <h2 v-if="level===2"><slot /></h2>
            // `
        })
        const vm = app.mount("#app");
    </script>
</body>

</html>

6.插件(plugin)的定义和使用

<!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>插件(plugin)的定义和使用</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 插件(plugin):其实就是把通过性的功能封装起来
         */

        //定义插件
        const myPlugin = {
            //插件被使用的时候,install函数就会执行
            install(app, options) {
                /**app:应用实例,options:接收传进来的数据
                 *console.log(app, options);
                 *通过app可以扩展很多需要的功能
                 **/
                app.provide("name", "张三"); //数据传值
                app.directive("focus", { //自定义指令
                    mounted(el) {
                        el.focus();
                    }
                })
                app.mixin({
                    mounted() {
                        console.log("mixin");
                    }
                })
            }
        }
        const app = Vue.createApp({
            template: `
                <myTitle />
            `,
        });
        app.component("myTitle", {
            inject: ["name"],
            template: `
                <div>
                    {{name}}
                    <input v-focus />
                </div>
            `
        })

        //使用插件
        app.use(myPlugin, {
            name: "xiaoming"
        });
        const vm = app.mount("#app");
    </script>
</body>

</html>

7.数据校验插件

<!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>数据校验插件</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    name: "zhangsan",
                    age: 18
                }
            },
            rules: {
                age: {
                    validate: (age) => {
                        return age > 18
                    },
                    message: "你已经成年"
                },
                name: {
                    validate: (name) => {
                        return name >= 4
                    },
                    message: "名字太长了"
                }
            },
            template: `
                <div>name:{{name}},age:{{age}}</div>
            `,
        });
        /**
         * 用插件封装一个能识别自己的定义的规则
         */
        const validatorPlugin = (app, options) => {
            app.mixin({
                created() {
                    for (let key in this.$options.rules) {
                        const item = this.$options.rules[key];
                        //console.log(key,item);
                        this.$watch(key, (value) => {
                            //console.log(key + "已经发生变化");
                            const result = item.validate(value);
                            if (!result) {
                                console.log(item.message);
                            }
                        })
                    }
                }
            })
        }
        app.use(validatorPlugin);
        const vm = app.mount("#app");
    </script>
</body>

</html>

8.Setup函数

<!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>Setup函数</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({

            template: `
                <div @click="handleClick">name:{{name}},age:{{age}}</div>
            `,
            /**
             * setup 会在create实例被完全初始化执行
             * setup函数属于Composition API
             * setup里的数据直接可以在组件中使用
             */
            setup(props, context) {
                return {
                    name: "zhangsan",
                    age: 19,
                    handleClick() {
                        alert("hello")
                    }
                }
            }
        });
        const vm = app.mount("#app");
    </script>
</body>

</html>

9.ref、reactive响应式引用的用法和原理

<!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>ref、reactive响应式引用的用法和原理</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        /**
         * 响应式引用的原理:通过proxy对数据进行封装,
         * 当数据变化时,模板等内容也随着变化。
         * ref():处理基础类型的数据。
         * reactive():处理非基础类型的数据。
         * ref和reactive都属于Comsition API,可以用来
         * 代替data
         */
        const app = Vue.createApp({
            template: `
                <div>name:{{nameObj.name}}</div>
            `,
            setup(props, context) {
                /**
                 * proxy把"lisi"变成proxy({value:"lisi"})
                 * 这样的一个响应式引用,改变它时,需要.value
                 * 来改变。即let name = ref("lise"),name.value="zhangsan"
                 */
                //     const {
                //         ref
                //     } = Vue; //引入ref才能使用它
                //     let name = ref("lisi");
                //     setTimeout(() => {
                //         name.value = "zhangsang";
                //     }, 2000);
                //     return {
                //         name
                //     }

                const {
                    reactive
                } = Vue;
                const nameObj = reactive({
                    name: "lisi"
                });
                setTimeout(() => {
                    nameObj.name = "zhangsan";
                }, 3000);
                return {
                    nameObj
                }
            }
        });
        const vm = app.mount("#app");
    </script>
</body>

</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>ref、reactive响应式引用的用法和原理</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            template: `
                <div>{{name}}</div>
            `,
            setup(props, context) {
                const {
                    reactive,
                    toRefs
                } = Vue;
                const nameObj = reactive({
                    name: "zhangsan"
                });
                setTimeout(() => {
                    nameObj.name = "lisi";
                }, 3000);
                /**
                 * toRefs底层:会把proxy({name:"zhangsan"})的格式
                 * 转换为{name:proxy({value:"zhangsan"})}的格式。
                 * 简单理解:如果不想在使用时用Obj.name的形式,想
                 * 直接用name就能获取值的话,就需要做一次toRefs的
                 * 转换即roResf(Obj),此时就可以直接使用name取值了。
                 */
                const {
                    name
                } = toRefs(nameObj);
                return {
                    name
                }
            }
        });
        const vm = app.mount("#app");
    </script>
</body>

</html>

10.toRef、context参数

<!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>toRef、context参数</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            template: `
                <div>{{age}}</div>
            `,
            setup(props, context) {
                const {
                    reactive,
                    toRef
                } = Vue;
                const data = reactive({
                    name: "zhangsan"
                });
                /**
                 * toRef:是用来处理默认值的,即取原来没有的数据,
                 * 本来是会报错的,但用toRef给其赋一个默认值,它
                 * 就不会报错了。toRef和toRefs不同,toRef后需要
                 * 用.value来改变值。
                 */
                const age = toRef(data, "age");
                setTimeout(() => {
                    age.value = "lisi"
                }, 3000)
                return {
                    age
                }
            }
        });
        const vm = app.mount("#app");
    </script>
</body>

</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>toRef、context参数</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            methods: {
                handleChange(){
                    alert('change');
                }
            },
            template: `
                <child title="hello" @change="handleChange">slot</child>
            `,

        });
        app.component("child", {
            template: `
                <div @click="handleClick">chlid</div>
            `,
            setup(props, context) {
                const { attrs,slots, emit } = context;
                /**
                 * attrs:接收父组件传过来的静态属性:title="hello"
                 * slots:接收父组件传过来的插槽
                 * emit:向往触发函数
                 */
                //console.log(attrs.title);
                // const { h } = Vue;
                // return () => h("div", {}, slots.default());
                function handleClick(){
                    emit("change");//向外触发change函数
                }
                return {
                    handleClick
                }
            }
        })
        const vm = app.mount("#app");
    </script>
</body>

</html>

11.使用Comsition API 开发 ToList

<!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>使用Comsition API 开发 ToList</title>
</head>

<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        //list的封装
        const listRelativeEffect = ()=>{
            const { reactive } = Vue;
            //创建非基础类型的响应式数据要reactive
            const list = reactive([]);
            const addItemToList = (item)=>{
                    list.push(item);
            }
            return { list, addItemToList }
        }
        //inpu的封装
        const inputtRelativeEffect = ()=>{
            const { ref } = Vue;
            const inputVal = ref('');
            const handleInputValueChange = (e)=>{
                inputVal.value = e.target.value;
            }
            return { inputVal,handleInputValueChange }
        }
        const app = Vue.createApp({
            setup(){
                const { list, addItemToList } = listRelativeEffect();
                const { inputVal,handleInputValueChange } = inputtRelativeEffect();
                return {
                    list,
                    addItemToList,
                    inputVal,
                    handleInputValueChange,
                }
            },
            template: `
                <div>
                    <div>
                        <input :value="inputVal" @input="handleInputValueChange" />
                        <div>{{inputVal}}</div>
                        <button @click="()=>addItemToList(inputVal)">提交</button>
                    </div>
                    <ul>
                        <li v-for="(item,index) in list">{{item}}</li>
                    </ul>    
                </div>
            `,
        });
        const vm = app.mount("#app");
    </script>
</body>

</html>

12.cmoputed计算属性

<!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>cmoputed计算属性</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            setup(){
                const { ref, computed } = Vue;
                const count = ref(0);
                const handleClick = ()=>{
                    count.value += 1;
                }
                const countAddFive = computed(()=>{
                    return count.value + 5;
                })
                return { count,handleClick,countAddFive }
            },
            template:`
            <div>
                <span @click="handleClick">{{count}}--{{countAddFive}}</span>
            </div>
            `
        });
       const vm = app.mount("#app");
    </script>
    
</body>
</html>

13.watch和watchEffect侦听器

<!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>watch和watchEffect侦听器</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            setup(){
                const { reactive, watch, watchEffect, toRefs } = Vue;
                const nameObj = reactive(
                    {
                        name:"张三",
                        englishName:"zhangsan"
                    }
                    );
                    /**
                     * watch
                     * 具有一定的懒惰性 lazy
                     * 参数可以获取到原始值和当前值
                    */
                watch([()=>nameObj.name,()=>nameObj.englishName],([curName,curEng],[prevName,prevEng])=>{
                    console.log(curName,prevName,'---',curEng,prevEng);
                })
                /**
                 * watchEffect
                 * 立即执行,没有惰性
                 * 不需要传递所侦听的内容,它会自动感知代码依赖
                 * 不需要传递很多参数,只需要传递一个回调函数
                 * 不能获取之前数据值
                 * 异步处理可以用watchEffect
                */
                const stop = watchEffect(()=>{
                    console.log(nameObj.name);
                    console.log(nameObj.englishName);
                    setTimeout(()=>{
                        stop();
                    },3000);
                })
                const { name, englishName } = toRefs(nameObj);
                return { name, englishName }
            },
            template:`
            <div>
                <div>
                    Name:<input v-model="name" />    
                </div>
                <div>
                    Name is:{{name}}
                </div>
                <div>
                    EnglishName:<input v-model="englishName" />    
                </div>
                <div>
                    EnglishName is:{{englishName}}
                </div>
            </div>
            `
        });
       const vm = app.mount("#app");
    </script>
    
</body>
</html>

14.生命周期函数的新写法

<!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>生命周期函数的新写法</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            setup(){
                /**
                 * Composition API里生命周期函数其实就是在原来的基础
                 * 上加on引入进来就可以使用了,使用还是原来的方法。
                */
                const { ref, onBeforeMount, onMounted, onBeforeUpdate } = Vue;
                const name = ref("zhangsan");
                onBeforeMount(()=>{
                    console.log("onBeforeMount");
                })
                onMounted(()=>{
                    console.log("onMunted");
                })
                onBeforeUpdate(()=>{
                    console.log("onBeforeUpdate")
                })
                const handleClick = ()=>{
                    name.value="lisi";
                }
                return { name, handleClick }
            },
            template:`
            <div @click="handleClick">
                {{name}}
            </div>
            `
        });
       const vm = app.mount("#app");
    </script>
    
</body>
</html>

15.Provide,Inject,DOM中的Ref的用法

<!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>Provide,Inject,DOM中的Ref的用法</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            setup(){
                const { provide,ref,readonly } = Vue;
                const name = ref("lisi");
                //readonly(name) 保证单项数据流
                provide("name",readonly(name));
                provide("changeName",(value)=>{
                    name.value = value;
                })
                return {  }
            },
            template:`
            <div>
                <child />
            </div>
            `
        });
        app.component("child",{
            setup(){
                const { inject } = Vue;
                const name = inject("name","如果取不到就显示这个默认值");
                //获取父组件传过来的方法
                const changeName = inject("changeName");
                const handleClick = ()=>{
                    //调用父组件传过来的方法进行更改
                    changeName("zhangsan");
                }
                return { name, handleClick }
            },
            template:`<div @click="handleClick">{{name}}</div>`
        })
       const vm = app.mount("#app");
    </script>
    
</body>
</html>

16.DOM中的Ref的用法

<!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>DOM中的Ref的用法</title>
</head>
<body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
            setup(){
                const { ref, onMounted } = Vue;
                const hello = ref(null);
                onMounted(()=>{
                    console.log(hello.value);//获取DOM元素
                })
                return { hello }
            },
            /**
             * 注:div里ref和上面引入的ref是不同的,
             * div里的ref是获取DOM元素的一个标记,而
             * 上面引入的ref是用来创建响应式数据的。
            */
            template:`
            <div>
                <div ref="hello">hello wrold</div>
            </div>
            `
        });
       const vm = app.mount("#app");
    </script>
    
</body>
</html>

17.vuecli脚手架

1).真正开发是需要脚手架来创建vue项目的
2).安装node,内包含npm(包管理工具)
3).在命令行安装nrm(镜像源):npm install nrm -g ; 
显示当前用的镜像源:
npm get registry
切换到淘宝镜像源
npm config set registry http://registry.npm.taobao.org

使用taobao镜像,在下载依赖包速度会快一点,nrm use taoba0
4).安装脚手架:npm install -g @vue/cli || 安装指定版本:npm install @vue/cli@版本号
5).vue项目的创建
在VScode里:Ctrl + ~ 进入控制台;
切换到自己想创建的目录:
eg:
PS D:\koa\vue3.0> cd vue-3
PS D:\koa\vue3.0\vue-3> cd vue21
PS D:\koa\vue3.0\vue-3\vue21> vue create 项目名

vue-cli脚手架工程目录简介

 18.vue-router

入口文件

import { createApp } from 'vue'
import App from './App.vue'
/**
 * 路由:是指根据url的不同,展示不同的内容
 */
import router from './router'

createApp(App).use(router).mount('#app')

路由文件

import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import LoginDome from '../views/LoginDome.vue'

const routes = [
  
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  //这种写法同步加载不推荐,当然首页可以这样写,其他路由就下面的写法即可
  {
    path: '/login',
    name: 'logindemo',
    component: LoginDome
  },
  {
    path: '/about',
    name: 'about',
    //这种写法是异步加载路由的意思(即按需加载)--推荐
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router

展示路由的文件

<template>
  <div>
  <nav>
    <!-- router-link:是路由跳转的标签 -->
    <router-link to="/">Home</router-link> |
    <router-link to="/login">Login</router-link> |
    <router-link to="/about">About</router-link>
  </nav>
  <!--router-view:用来展示路由跳转到的地址的内容  -->
  <router-view/>
  </div>
</template>

19.vuex数据仓库

以下代码可以参考图来理解,vuex数据仓库,在其他组件进行修改的流程,确实稍微有点复杂

需要修改数据的组件

<template>
  <div>
    <img alt="Vue logo" src="../assets/logo.png">
    <h1 @click="handleClick">{{myName}}</h1>
  </div>
</template>

<script>
export default {
  name: 'HomeView',
  computed:{
    myName(){
      //获取vuex仓库中state里的数据
      return this.$store.state.name;
    }
  },
  methods: {
    handleClick(){
      /**
       * 想要修改vuex仓库里的数据,vuex要求
       * 第一要派发(dispatch)一个action(change)
       */
      this.$store.dispatch("change","wangwu");//wangwu是要修成的数据
    }
  },
}
</script>

 使用Composition API修改数据文件

<template>
  <div>
    <h1 @click="handleClickChange">{{name}}</h1>
  </div>
</template>

<script>
import { useStore } from 'vuex';
import { toRefs } from 'vue';
//import axios from 'axios';
export default {
  name:"AboutViews",
  setup(){
    //获取全局的数据对象
    const store = useStore();
    //const name = store.state.name;
    const {name} = toRefs(store.state);
    const handleClickChange = ()=>{
      store.dispatch("changeName","zhaoliu");
    }
    //vue 使用axios发送ajax请求
    // axios.get('接口地址')
    // .then((response)=>{
    //   console.log(response);
    // })
    return{ name,handleClickChange }
  }
}
</script>

vuex仓库文件

import { createStore } from 'vuex'
/**
 * vuex:是一个数据管理框架
 * vuex创建了一个全局唯一的框架,用来存放全局的数据
 */
export default createStore({
  state: {
    /**
     *state存放全局的数据,
     *任何组件都可以使用这里的数据
    */
    name:"zhangsan"
  },
  getters: {
  },
  mutations: {
    /**
     * 第四接收change提交过来的一个叫muta的mutation,
     * 并把muta转为一个函数执行
     */
    muta(store,str){
      /*第五修改你需要修改的数据*/
      this.state.name = str;
    },
    mutas(store,str1){
      this.state.name = str1;
    }
  },
  actions: {
    /**
     * 第二actions会感知到你派发了一个叫做
     * change的action,并把change转为一个
     * 函数执行。
     */
    change(store,str){
      /**
       * 第三change函数的执行会提交一个commit
       * 触发一个mutation(muta)
       * 此处也可以处理异步操作
       */
      this.commit("muta",str)
    },
    changeName(store,str){
      setTimeout(()=>{
        this.commit("mutas",str);
      },5000)
      
    }
  },
  modules: {
  }
})

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值