VUE3.0学习笔记

前端学习笔记

VUE3.0

  • v-for 循环
    • vue
      Vue.createApp({
      data(){
      return{
      list = ['1','2','3']
      }
      },
      template: `
      <div>
      <li>
      <todo-item v-for='(item,index) of list' >
      </li>
      </div>
      `
      })
  • v-bind 绑定变量
    • vue
      <div>
      <todo-item
      v-for='(item,index) of list'
      v-bind:content='item'
      v-bind:indexs='index'
      />
      </div>
  • app.component 每个组件都是可以提出单独来操作
    • vue
      // 注册方法组件
      app.component('todo-item',{
      // 获取值之前v-bind的值
      props: ['content','indexs'],
      template:`<li>{{content}} ---- {{indexs}}</li>`
      })
  • app.mount(‘id’) 注册绑定

  • 生命周期函数在某一个时间会自动执行的函数

    • beforecreate
    • created

各种属性

  • methods:只要页面重新渲染,才会重新去计算
  • computer:当计算属性的内容发生变更的时候,才会重新执行计算(计算属性带有缓存所以相对的要高效一些)
// 两者之间的对比当我们在页面上vm.$data.message时候totle变量是不会改变的
<script>
    const app = Vue.createApp({
        data() {
            return {
                message: "hello world",
                count: 1,
                price: 5, 
            }
        },
        methods: {
            handleClick() {
                console.log('你好强')
            },
            getTotal(){
                return Date.now()
            }
        },
        // 计算属性
        computed: {
            totle() {
                return Date.now() + this.count
            }
        },
        // template: `
        // <div @click="handleClick">
        //     {{message}}
        // </div>`
        template:`
        <div>
            {{ message }}    {{totle}}
        </div>
        `

    })
    const vm = app.mount('#root')
</script>
  • watcher:监听功能和computerd都能够实现的功能,建议使用computed更加简洁
        watch: {
            price(news,olds) {
                this.newtotle = this.count * news
            }
        }
  • vue中使用样式
<head>
    <style>
        .red {
            color: red;
        }
        .green {
            color: green;
        }
    </style>
</head>
<script>
    const app = Vue.createApp({
        data() {
            return {
                colock: 'red',
                // 对象来传递参数
                classobject: {red: false,green: true},
                // 数组来传递参数
                classarray: ['red','green'],
                // 写多种样式
                styleclass: {
                    color: 'red',
                    background: 'yellow',
                }
            }
        },
        template:`
        <div :style="styleclass"> hello workd
            <demo />    
        </div>
        `
    });

    app.component('demo',{
        template: `<div :class="$attrs.classobject"> niubi </div>
        <div> test </div>
        `
    })
    const vm = app.mount('#root')
</script>
  • v-if / v-show 在用法上的差异,一个直接删除元素,一个直接操作style
<script>
    const app = Vue.createApp({
        data() {
            return {
                show: false,
            }
        },
        template:`
            <div v-if='show'> 你好强</div>
            <div v-show='show'> 你超强</div>
        `
    });
    const vm = app.mount('#root')
</script>
  • 对methods的函数中的变量进行操作的方式
<script>
    const app = Vue.createApp({
        data() {
            return {
                list: ['hello','little','boy'],
                listobject: {
                    firstname: 'niubi',
                    lastername: 'chong',
                    job: '你好强',
                }
            }
        },
        methods: {
            handleAdd(){
                // 1.可以使用变更函数来处理对象 push,pop,shift,splice,sort,reverse

                //this.list.push("grond SB")
                //this.list.pop();
                //this.list.shift()
                //this.list.sort

                // 2.直接替换数组
                // 3.直接更新数据的内容
                this.listArray = ['boy','world'].filter(item => item === 'byte');
            }
        },
        template: `
            <div v-for="(value,index) in list" >
                {{value}} -- {{index}}
            </div>
            <button @click="handleAdd">新增对象</button>
        `
    })
    const vm = app.mount('#root')
</script>

1.列表渲染循环

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id='root'>hello world</div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                list: ['hello','little','boy'],
                listobject: {
                    firstname: 'niubi',
                    lastername: 'chong',
                    job: '你好强',
                }
            }
        },
        methods: {
            handleAdd(){
                // 1.可以使用变更函数来处理对象 push,pop,shift,splice,sort,reverse

                //this.list.push("grond SB")
                //this.list.pop();
                //this.list.shift()
                //this.list.sort

                // 2.直接替换数组
                // 3.直接更新数据的内容
                this.listArray = ['boy','world'].filter(item => item === 'byte');
            }
        },
        template: `
            <div v-for="(key,value,index) in listobject" :value="index">
                <div v-if="value !== 'lastername'">
                    {{value}} -- {{index}}
                </div>
            </div>
            <div v-for="index in 10">{{index}}</div>
            <button @click="handleAdd">新增对象</button>
            <div> This is Test Vue</div>
        `
    })
    const vm = app.mount('#root')
</script>
</html>

2.vue事件绑定

  • 如果在触发按钮的时候需要调用多个methods方法则可以使用
    • <button @click="func1(),func2()">按钮加一</button>
  • 事件修饰符:
    • @click.stop:停止冒泡
    • @click.self:只有是触发本身的情况下才触发 后续操作
    • @click.one:只是执行一次
    • @click.prevent:阻止默认行为
    • @click.capture:从外到内捕获
    • scroll.passive:提高执行的性能
    • prevent
    • capture
  • 案件修饰符
    • enter
    • tab
    • delete
    • esc
    • up
    • down
    • left
    • right
  • 鼠标修饰符
    • left,right,middle
  • 精确修饰符
    • exact
  • 事件触发响应修饰符
    • lazy
  • 去除前后的空格的修饰符
    • trim:中间空格不会去除
<script>
    const app = Vue.createApp({
        data() {
            return {
                counter : 0
            }
        },
        methods: {
            handleDivClick(){
                alert('div clicked')
            },
            handleAdd(num,event){
                // 打印事件调用的目标
                console.log(event.target);
                this.counter += num;
            }
        },
        template:`
        <div>
            {{counter}}
            <div @click='handleDivClick'>
                <Button @click.stop="handleAdd(2,$event)">加一</Button>
                </div>
        </div>`
    });
    const vm = app.mount('#root')
</script>

3.双向绑定

  • 多种条件下的双向绑定
<script>
    const app = Vue.createApp({
        data() {
            return {
                message: [],
                message2: '',
                message3: '',
                message4: [],
                options: [
                    {text: '你',value: '你'},
                    {text: "好",value: {value: '好'}},
                    {text: "强",value: '强'},
                ],
            }
        },
        template:`
        <div>
            {{message}}  
            <div>
                牛逼 <input type="checkbox" v-model="message" value="牛逼" />  
                好强 <input type="checkbox" v-model="message" value="好强" />   
            </div>
            --- {{message2}}
            <div>
                测试 <input type="radio" v-model="message2" value="测试" />
                好强 <input type="radio" v-model="message2" value="好强" /> 
            </div>
            <div>
                {{message3}}
                <select v-model="message3">
                    <Option disabled value="">请选择内容</Option>
                    <Option value="A" key="">A</Option>
                    <Option value="V" key="">V</Option>    
                    <Option value="C" key="">C</Option>        
                </select>    
            </div>

            <div>
                {{message4}}
                <select v-model="message4" multiple>
                  <Option v-for='item in options' :value="item.value">{{item.text}}</Option>
                </select>    
            </div>
        </div>`
    });
    const vm = app.mount('#root')
</script>

Vue的组件

  • 组件的定义:
    • 组件具有复用性
    • 全局组件,只要定义了不管哪里都能去使用,但是性能不高
    • 命名:小写+-+name
<script>
    const app = Vue.createApp({
        // 组件是具有复用性的,且相互之间是不影响的
        template: `<div>
            <counter />
            <counter />
            <counter />
            <counter-parent />
            </div>`
    });
    app.component('counter-parent',{
        template: `<counter />`
    })
    app.component('counter',{
        data() {
            return {
                count: 1
            }
        },
        template: `<div @click='count += 1'>{{count}}</div>`
    })
    const vm = app.mount('#root')
</script>
  • 子组件的用法
    • const定义一个变量,然后在app中去声明变量
    • JS变量不支持-作为名字,所以一般都是用驼峰命名法
    • 建议命名是大小开头+驼峰
    • 局部组件使用的时候,咬做一个名字和组件的映射,不写映射vue底层也会尝试自己做
<script>
    const counter = {
        data() {
            return {
                count: 1
            }
        },
        template: `<div @click='count += 1'>{{count}}</div>`
    }
    const app = Vue.createApp({
        components: {counter:counter},
        // 组件是具有复用性的,且相互之间是不影响的
        template: `<div>
            <counter />
            </div>`
    });
    const vm = app.mount('#root')
</script>

1.组件的传值和值的校验

<script>
    const app = Vue.createApp({
        data() {
            return {
                num: 123,
                // 传递一个函数
                fun: () => {alert(123) },
                // required的检测
                re: 123,
                // default和判断值的范围
                numbers: 123,
            }
        },
        // 组件是具有复用性的,且相互之间是不影响的
        // 静态的参数只能传递string,动态可以任意类型
        template: `<div>
            <test content="你好强" :example="num" :func="fun" :res='re' :nu="numbers" />
            </div>`
    });
    // 设置全局变量
    app.component('test',{
        // 接受来自外部的传入的参数,且进行校验
        // required 必填否则报错
        // default 给默认值
        props: {
            content: String,
            example: Number,
            // 对函数类型的校验
            func: Function,
            // 对必填的校验
            res: {
                type: String,
                required: true
            },
            // default和大小
            nu: {
                type: Number,
                validator: function(value) {
                    return value<1000
                },
                default: function() {
                    return 123
                }
            }
        },
        methods: {
            handleClick(){
                alert(123456789);
                this.fun;
            }
        },
        template: `<div @click='this.handleClick'>{{content}}--{{typeof example}}--{{typeof func}}</div>
        <div>{{res}}--{{nu}}</div>`
    });
    const vm = app.mount('#root');
</script>

2.父子组件中的检验

  • 父子组件间的变量传递:静态和动态以及相关的检验方式
<script>
    const app = Vue.createApp({
        data(){
            return {
                // 传递函数
                num: () => {alert(123)},
                // 进行必须校验
                nums: "123",
                // 默认值
                defaults: "",
                // 判断是否符合范围
                ranges: 1224,
            }
        },
        template: `
        <div>
            <test :content="num" :nums="nums" :range="ranges" />  
        </div>
        `
    });
    app.component('test',{
        props: {
            content: Function,
            nums: {
                type: Number,
                required: true,
            },
            de: {
                type: String,
                default: "你好强",
            },
            range: {
                type: Number,
                validator: function(value){
                    return value<1000;
                },
                default: function() {
                    return 111;
                }
            }
        },
        methods: {
            handleClick(){
                alert(456)
                this.content();
            }
        },
        template: `
        <div @click="this.handleClick">{{typeof content}}</div>
        <div>required -> {{typeof nums}}</div>
        <div>default -> {{de}}</div>
        <div>{{range}}</div>
        `
    })
    const vm = app.mount("#root")
</script>

3.单项数据流

  • Vue中父组件传递过来的变量,子组件是只读的无法修改的
<script>
    const app = Vue.createApp({
        data() {
            return {
                params: {
                    content: 123,
                    a: "asd",
                },
                // 带横线的变量传递到子组件
                content: 12345,
                // 单数据流的方式
                num: 1,
            }
        },
        template: `<div><test  v-bind="params" :content-ac="content" /></div>
        <div> <counter :count="num" /></div>
        `
    })
    app.component('test',{
        props: ['content','a','content-ac'],
        template: `<div>{{content}}--{{a}}--{{contentAc}}</div>`
    })
    app.component('counter',{
        props: ['count'],
        data() {
            return {
                myCount: this.count,
            }
        },
        template: `<div @click=" myCount +=2">{{myCount}}</div>`
    })

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

4.当不使用props时候如何接收变量

<script>
    const app = Vue.createApp({
        data() {
            return {
                msg1: 1123,
            }
        },
        template: `<div><test  msg="hello" :msg1="msg1" /></div>
    `
    });
    app.component('test',{
        //不使用props属性如何接收来自父组件的变量
        mounted() {
            console.log(this.$attrs.msg)
        },
        template: `
        <div :msg="$attrs.msg">test</div>
        <div :msg="$attrs.msg1">test</div>
        <div :msg="$attrs">test</div>
        `
    });

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

5.父子组件通过事件传递信息

<script>
    const app = Vue.createApp({
        data() {
            return {
                msg: 1,
            }
        },
        methods: {
            handleClick(){
                this.msg += 1
            }
        },
        template: `<div><test  :msg="msg" @add-one="handleClick" /></div>
    `
    });
    app.component('test',{
        props:["msg"],
        mounted() {
            console.log(this.msg)
        },
        methods: {
            handleOne(){
                this.$emit('addOne')
            }
        },
        template: `
        <div @click="handleOne" >{{msg}}</div>
        `
    });

    const vm = app.mount('#root')
</script>
  • 事件在子组件处理完成后赋值给父组件处理
<script>
    const app = Vue.createApp({
        data() {
            return {
                msg: 1,
            }
        },
        methods: {
            handleClick(paps){
                this.msg = paps
            }
        },
        template: `<div><test  :msg="msg" @add="handleClick" /></div>
    `
    });
    app.component('test',{
        props:["msg"],
        emits: {
            add: (msg) => {
                if(msg>0){
                    return true
                }
                return false
            }
        },
        methods: {
            handleOne(){
                this.$emit('add',this.msg+3);
            }
        },
        template: `
        <div @click="handleOne" >{{msg}}</div>
        `
    });
    const vm = app.mount('#root')
</script>
  • 父子组件的高级用法
    • v-model:变量="变量" + 子组件 update:变量
<script>
    const app = Vue.createApp({
        data() {
            return {
                msg1: 1,
            }
        },
        methods: {
            handleClick(paps){
                this.msg1 = paps
            }
        },
        template: `<div><test  v-model:msg="msg1" /></div>
    `
    });
    app.component('test',{
        props:["msg"],
        emits: {
            add: (msg) => {
                if(msg>0){
                    return true
                }
                return false
            }
        },
        methods: {
            handleOne(){
                this.$emit('update:msg',this.msg+3);
            }
        },
        template: `
        <div @click="handleOne" >{{msg}}</div>
        `
    });
    const vm = app.mount('#root')
</script>
  • 自定义修饰符父子组件的用法
<script>
    const app = Vue.createApp({
        data() {
            return {
                msg1: 'a',
            }
        },
        template: `<div><test  v-model.uppercase="msg1" /></div>
    `
    });
    app.component('test',{
        props:{
            // 传入的变量类型
            'modelValue': String,
            // 如果传入的为空则把变量置为空,固定的句式
            'modelModifiers': {
                default: ()=>({})
            }
        },

        methods: {
            handleOne(){
                // 将传入的对象转化为大写输出
                let newValue = this.modelValue + "b";
                console.log(this.modelModifiers)
                // 如果传入的对象为真则进行转换
                if (this.modelModifiers.uppercase){
                    newValue = newValue.toUpperCase();
                }
                this.$emit('update:modelValue',newValue);
            }
        },
        template: `
        <div @click="handleOne" >{{modelValue}}</div>
        `
    });
    const vm = app.mount('#root')
</script>

6.父子组件传递dom/元素等方法

  • 父组件可以直接传递插槽的方式去使用多种情况,子组件用slot去接收,但是不能绑定事件的
    • 父模板里面调用的数据属性,使用的都是父模板的数据
    • 子模板里面的调用数据属性,使用的也是自模板的数据
<script>
    const app = Vue.createApp({
        data() {
            return {
                text: "提交"
            }
        },
        template: `
        <myform>
            <div>{{text}}</div>
        </myform>
        <myform>
            <button>{{text}}</button>
        </myform>
        <myform>
            <test1 />
        </myfrom>
        `
    });
    app.component('test1',{
        template:`
        <div>好强</div>
        `
    })
    app.component('myform',{
        methods: {
            handleClick() {
                alert("测试")
            }
        },
        template: `
        <div>
            <input />
            <space @click="handleClick">
                <slot></slot>
            </space>  
        </div>
        `
    })
    const vm = app.mount('#root')
</script>
  • 插槽的高级用法- 作用域插槽
    • 当子组件的内容需要由父组件渲染决定的时候
<script>
    const app = Vue.createApp({
        data() {
            return {
                text: "提交"
            }
        },
        template: `
        <list v-slot="{item}">
            <div>{{item}}</div>
        </list>
        `
    });
    app.component('list',{
        data() {
            return {
                list: [1,2,3,4],
            }
        },
        template:`
        <div>
            <slot v-for="item in list" :item="item"></slot>    
        </div>
        `
    })
    const vm = app.mount('#root')
</script>

7.vue中的动态组件和异步组件

  • 动态组件:根据数据的变化,结合下compoent标签,来随时的动态切换组件,常和keep-alive联用
<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'
                }
            }
        },
        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</div>`
    });

    const vm = app.mount('#root')
</script>
  • 异步组件:异步的执行某些代码逻辑
<script>
    const app = Vue.createApp({
        template: `
        <div>
            <common-item />
            <async-common-item />
        </div>
        `
    });
    app.component('common-item',{
        methods: {
            handle(){
                alert(123)
            }
        },
        template: `
        <div>
            <input />
            <button @click="handle">提交</button>
            </div>`
    });
    app.component('async-common-item',Vue.defineAsyncComponent(()=>{
        return new Promise((resole,reject)=>{
            setTimeout(()=>{
                resole({
                    template: `<div> this is an async component</div>`
                })
            },4000)
        })
    }));

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

8.细节补充说明

  • v-once:让某个元素或者标签只是渲染一次
  • ref:当页面渲染完成加载完成后需要拿到dom则可以使用ref来获取
  • provide / inject:多组件之间的值的传递
<script>
    const app = Vue.createApp({
        data() {
            return {
                count: 1,
                count1: 2,
            }
        },
        provide: {
            cc: "好强"
        },
        mounted() {
            console.log(this.$refs.count1)
            // 渲染后改变标签的值
            this.$refs.count1.innerHTML ='hello'
            // 调用子组件的方法
            this.$refs.common.sayHello()
        },
        template: `
        <div @click="count +=1" v-once>
            {{count}}
        </div>
        <div ref="count1">
            {{count1}}
        </div>
        <commot ref="common" :cc="cc"/>
        `
    });
    app.component("commot",{
        methods: {
            sayHello (){
                alert("hello")
            }
        },  
        template: `<div> func 2 </div>
        <commot-children />`
    })
    app.component("commot-children",{
        inject: ['cc'],
        template: `
        <div>
            {{cc}}    
        </div>`
    })
    const vm = app.mount("#root")
</script>

Vue中的动画和过渡

  • 简单实现动画的触发和过渡效果的使用
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue动画和过渡</title>
    <script src="https://unpkg.com/vue@next"></script>
    <style>
        /*动画*/
        @keyframes leftToRight {
            0% {
                transform: translateX(-100px);
            }
            50% {
                transform: translateX(-50px);
            }
            0%{
                transform: translateX(0px);
            }
        }
        .animation {
            animation: leftToRight 3s;
        }
        /*过渡*/
        .animationcolor {
            transition: 3s background-color ease;
        }
        /*
        .bule {
            background: blue;
        }
        .green {
            background: green;
        }
        */
    </style>
<script>
    const app = Vue.createApp({
        data() {
            return {
                animate: {
                    animation: false,
                    animationcolor: true,
                },
                styleObj: {
                    background: 'bule'
                }
            }
        },
        methods: {
            handleClick() {
                this.animate.animation = true;
            },
            handleColor() {
                if(this.styleObj.background === 'blue'){
                    this.styleObj.background = 'green';
                }else {
                    this.styleObj.background = 'blue';
                }
            }
        },
        template: `<div :class="animate" :style="styleObj">你好强</div>
        <button @click="handleClick">点击切换动画</button>
        <button @click="handleColor">点击切换底色</button>
        `
    })
    const vm = app.mount("#root")
</script>

1.单元素和单组件的入场出场动画

  • 实现单组件单元素的效果
// transitin在css可以定义的别名称呼如下
<transition
enter-from-class=""
enter-to-class=""
enter-active-class=""
leave-from-class=""
leave-active-class=""
leave-to-class="">
</transition>
  • 使用例子
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue动画和过渡</title>
    <script src="https://unpkg.com/vue@next"></script>
    <style>
        @keyframes shake {
            0% {
                transform: translateX(-100px);
            }
            50% {
                transform: translateX(-50px);
            }
            100% {
                transform: translateX(50px);
            }
        }
        /*在整个动画的过程中如何去执行*/
        .hello-leave-active {
            animation: shake 3s ease-out;
        }
        .hello-enter-active {
            animation: shake 0.5s ;
        }

    </style>
</head>
<body>
    <div id="root">hello world</div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                show: false,
            }
        },
        methods: {
            handleClick() {
                this.show= !this.show;
            }
        },
        template: `
        <div>
            <transition name="hello">
                <div v-if="show" >你好强</div>    
            </transition>
            <button @click="handleClick">切换动作效果</button>    
        </div>
        `
    })
    const vm = app.mount("#root")
</script>
  • 动画和过渡联合使用的demo
    • type=”transition”:表示不管动画多久结束只要transition到时间动画也一样结束
    • :duration=”{enter:1000,leave:2000}”:表示不管动画和过渡多少时间,duration到点就全部一起结束
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue动画和过渡</title>
    <script src="https://unpkg.com/vue@next"></script>
    <style>
        @keyframes shake {
            0% {
                transform: translateX(-100px);
            }
            50% {
                transform: translateX(-50px);
            }
            100% {
                transform: translateX(50px);
            }
        }
        /*在整个动画的过程中如何去执行*/
        .v-enter-from{
            color: red;
        }
        .hello {
            animation: shake 5s ;
            transition: color 3s ease-in;
        }
        .bye {
            animation: shake 3s;
            color: red;
            transition: all 2s ease-in;
        }

    </style>
</head>
<body>
    <div id="root">hello world</div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                show: false,
            }
        },
        methods: {
            handleClick() {
                this.show= !this.show;
            }
        },
        template: `
        <div>
            <transition type="transition" :duration="1600"
                enter-active-class="hello"
                leave-active-class="bye"
            >
                <div v-show="show" >你好强</div>    
            </transition>
            <button @click="handleClick">切换动作效果</button>    
        </div>  
        `
    })
    const vm = app.mount("#root")
</script>
  • 引入第三方的css组件的demo
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue动画和过渡</title>
    <script src="https://unpkg.com/vue@next"></script>
    <link
    rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
    />
</head>
<body>
    <div id="root">hello world</div>
</body>
<script>
    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__flash"
            >
                <div v-show="show" >你好强</div>    
            </transition>
            <button @click="handleClick">切换动作效果</button>    
        </div>  
        `
    })
    const vm = app.mount("#root")
</script>
  • 使用JS的方法进行动画
<transition
:css="false"
@before-enter="handleBeforeEnter"  //可以接收的参数el
@enter="handleEnterActive"  //可以接收的参数el.done
@after-enter="handleEnterEnd" //可以接收的参数el
@before-leave=""   //可以接收的参数el
@leave=""  //可以接收的参数el.done
@leave-after="" //可以接收的参数el >   
</transition>
  • transition 单元素的实现demo
<body>
    <div id="root">hello world</div>
</body>
<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 animation = setInterval(() => {
                    const color = el.style.color
                    if (color === "red"){
                        el.style.color = "green";
                    }else{
                        el.style.color = "red";
                    }
                },500) 
                // 定时清理终止动画状态
                setTimeout(() => {
                    clearInterval(animation);
                    // 调用done后after-enter会告知停止
                    done();
                },3000)
            },
            handleAfter() {
                alert("真的好强!")
            }
        },
        template: `
        <div>
            <transition 
                :css="false"
                @before-enter="handleBeforeEnter"
                @enter="handleEnterActive"
                @after-enter="handleAfter"
            >
                <div v-show="show" >你好强</div>    
            </transition>
            <button @click="handleClick">切换动作效果</button>    
        </div>  
        `
    })
    const vm = app.mount("#root")
</script>

2.组件和元素的切换动画的实现

  • 多个单元素之间的切换动画实现
    • v-if 和 v-else = 为真时候动作和为假时候动作
    • <transition mode="out-in">:动画先隐藏再展示
    • <transition mode="in-out">:动画进入先展示后隐藏
    • 如果不加mode方法则是同时一起执行
    • <transition appear>:初次显示的时候默认也给带上动画效果
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>组件和元素的切换动画的实现</title>
      <script src="https://unpkg.com/vue@next"></script>
      <style>
          .v-leave-to {
              opacity: 0;
          }
          /* 入场 */
          .v-enter-from {
              opacity: 0;
          }
          /* 动画中 */
          .v-leave-active,
          .v-enter-active {
              transition: opacity 1s ease-in;
          }
          .v-leave-to,
          .v-enter-to {
              opacity: 1;
          }
      </style>
    </head>
    <body>
      <div id="root">hello world</div>
    </body>
    <script>
      const app = Vue.createApp({
          data() {
              return {
                  show: true,
              }
          },
          methods: {
                  handleClick() {
                      this.show = !this.show
                  }
          },
          template: `
              <div>
                  <transition mode="out-in" appear>
                      <div v-if="show">你好强</div>
                      <div v-else="show">太TM强了</div>
                  </transition> 
                  <button @click="handleClick">单元素切换动画</button>
              </div>
              `
    
      })
      const vm = app.mount("#root")
    </script>
    
  • 多个单组件之间切换动画实现

// 静态组件的写法
<script>
    const componentA = {
        template: `<div>你好强</div>`
    }
    const componentB = {
        template: `<div>太TM强了</div>`
    }
    const app = Vue.createApp({
        // 子组件用法
        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>
            `
    })
</script>
  • 动态组件动画的用法
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件和元素的切换动画的实现</title>
    <script src="https://unpkg.com/vue@next"></script>
    <style>
        .v-leave-to {
            opacity: 0;
        }
        /* 入场 */
        .v-enter-from {
            opacity: 0;
        }
        /* 动画中 */
        .v-leave-active,
        .v-enter-active {
            transition: opacity 1s ease-in;
        }
        .v-leave-to,
        .v-enter-to {
            opacity: 1;
        }
    </style>
</head>
<body>
    <div id="root">hello world</div>
</body>
<script>
    const componentA = {
        template: `<div>你好强</div>`
    }
    const componentB = {
        template: `<div>太TM强了</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>

3.列表多元素的动画实现

  • <transition-group>对于列表则使用了group
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>列表动画的实现</title>
    <script src="https://unpkg.com/vue@next"></script>
    <style>
        .v-enter-from{
            opacity: 0;
            transform: translateY(30px);
        }
        .v-enter-active {
            transition: all 1s ease-in;
        }
        .v-enter-to {
            opacity: 1;
            transform: translateY(0px);
        }
        .v-move {
            transform: all 0.6s ease-in;
        }
        .list-item {
            display: inline-block;
            margin-right: 10px;
        }
    </style>
</head>
<body>
    <div id='root'>hello world</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>

4.状态动画的实现

<script>
    const app = Vue.createApp({
        data() {
            return {
                num: 1,
                animateNum: 1,
                show: true,
            }
        },
        methods: {
            handleClick(){
                this.num = 10;
                if(this.animateNum<this.num)
                this.show = !this.show
                animation = setInterval(()=>{
                    this.animateNum += 1;
                    if(this.animateNum === 10){
                        clearInterval(animation)
                        this.show = !this.show
                    }
                },100);
            }
        },
        template: `
        <div>
            <div>
                {{animateNum}}    
            </div>
            <button v-show="show" @click="handleClick">添加数值</button></button>
        </div>
        `
    })
    const vm = app.mount('#root')
</script>

Vue中高级用法

1.Mixin混入的语法

  • mixin:将某一些内容混入到内部
    • 组件中的data优先级>混 入的优先级
    • 生命周期函数,先执行mixin的,后执行组件中的
    • methods组件中有就会覆盖mixin的、
    • 局部的Mixin,在子组件中想要去使用就必须声明
    • 全局mixin:app.mixins
    • 自定义的属性:组件中的属性优先级高于mixin的属性优先级
    • Vue-3后不是很建议去使用mixin,会增加排障难度
<script>
    const myMixin = {
        myNum: 4,
        data() {
            return {
                number: 2,
                count: 123,
            }
        },
        created() {
            console.log("myMixin created")
        },
    }
    const app = Vue.createApp({
        myNum: 3,
        data() {
            return {
                number: 1
            }
        },
        mixins: [myMixin],
        methods: {
            handleClick() {
                console.log("强")
            }
        },
        created() {
            console.log("vue created")
        },
        template:`
            <div>{{number}}</div>  
            <div>vue->{{count}}</div>  
            <div>my-num->{{this.$options.myNum}}</div>
            <child />
            <button @click="handleClick">测试</button>
        </div>
        `
    });
    app.component('child',{
        mixins: [myMixin],
        created() {
            console.log("child created")
        },
        template: `
        <div>{{count}}</div>`
    })
    // 调整mixins的优先级方法
    app.config.optionMergeStrategies.myNum = (mixinVal,appValue) => {
        return mixinVal || appValue
    }
    const vm = app.mount("#root")
</script>

2.如何编写vue的自定义指令

  • 全局指令demo
<script>
    const app = Vue.createApp({
        template: `
        <div>
            <input v-focus />
        </div>
        `
    });
    app.directive('focus',{
        mounted(el) {
            // 自动聚焦
            el.focus();
        },
    })
    const vm = app.mount("#root")
</script>
  • 局部指令demo
<script>
    // 局部指令
    const directives ={
        focus: {
            mounted(el) {
                // 自动聚焦
                el.focus();
            },
        }
    }
    const app = Vue.createApp({
        directives: directives,
        template: `
        <div>
            <input v-focus />
        </div>
        `
    });
    const vm = app.mount("#root")
</script>

3.Vue3新功能Teleport

  • teleport:可以将某些组件中的某些元素挂载到指定的位置上面去
    • 比如挂载到body/一些标签上
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue的自定义指令编写指南</title>
    <script src="https://unpkg.com/vue@next"></script>
    <style>
        .area {
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%,-50%);
            width: 200px;
            height: 300px;
            background: black;
        }
        .msk{
            position: absolute;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            background: red;
            opacity: 0.5;
            color: white;
            font-size: 100px;
        }
        .msky{
            position: absolute;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            background: black;
            opacity: 1;
            color: white;
            font-size: 100px;
        }
    </style>
</head>
<body>
    <div id="root">hello world</div>
    <div id="hello"></div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                distance: 20,
                show: false,
                message: "太TM强了"
            }
        },
        methods: {
            handleClick(){
                this.show = !this.show
            }
        },
        template: `
        <div class="area">
            <Button @click="handleClick">hold屏幕</Button>
            <teleport to="body">
                <div class="msk" v-show="show"></div>
            </teleport>
            <teleport to="#hello">
                <div class="msky" v-show="show">{{message}}</div>
            </teleport>
        </div>
        `
    });
    app.directive('pos',(el,binding)=>{
        el.style[binding.arg] = (binding.value + "px")
    })
    const vm = app.mount("#root")
</script>

4.render函数的简单用法

  • render本质:template -> 编译解析后render函数 -> h函数 -> 虚拟的Dom -> 展示页面
    • 可以俄罗斯套娃无限套下去
<script>
    const app = Vue.createApp({
        template: `
        <my-title :level="2">
            hello    
        </my-title>
        `
    })
    app.component('my-title',{
        props:['level'],
        render() {
            const {h} = Vue;
            // 虚拟DOM:Dom节点的虚拟表述
            //参数一:定义标签,参数二:attributes()标签上的属性,参数三:标签中带的文本
            return h('h'+this.level,{},[
                this.$slots.default(),
                h('h4',{},"真的TM强")
            ])
        },
    })
    const vm = app.mount("#root")
</script>

5.插件的定义和使用

  • install(app,options)
<script>
    // plugin插件,把通用的功能封装起来
    const myPlugin = {
        install(app,options){
            app.provide('name','ZWX 你好强')
            app.directive('focus',{
                mounted(el) {
                    el.focus();
                }
            })
        }
    };
    const app = Vue.createApp({
        template: `
        <my-title />
        `
    });
    app.component('my-title',{
        inject: ['name'],
        template:`
        <div>
            {{name}}    
            <input v-focus/>
        </div>
        `
    })
    app.use(myPlugin)
    const vm = app.mount("#root")
</script>

6.简单的自定义校验器

  • 在修改参数值的时候希望对目标值进行校验
<script>
    // 对数据校验的插件
    const validatoPlugin= (app,options) => {
        app.mixin({
        created() {
            for (let key in this.$options.rules){
                const item = this.$options.rules[key];
                this.$watch(key,(value)=>{
                    const result = item.validate(value);
                    if (!result) console.log(item.message)
                })
            }
        },
    })
    }

    const app = Vue.createApp({
        data() {
            return {
                name: '你好强',
                age: '24',
            }
        },
        rules: {
            age: {
                validate: age => age > 25,
                message: "too young,to simple",
            },
            name: {
                validate: name => name >= 4,
                message: "name too short",
            }
        },
        template: `
        <div>name:{{name}},age:{{age}}</div>
        `
    });
    app.use(validatoPlugin);
    const vm = app.mount("#root")
</script>

Vue-CompositionAPI

  • CompositionAPI建立在setup函数上内部是无法使用this的因为对象没有被挂载
    • 它不能调用实例上的方法,但是实例上的能调用它
<script>
    const app = Vue.createApp({
        template: `
        <div @click="handleClick">{{name}}</div>
        `,
        methods: {
            test() {
                console.log(this.$options.setup());
            }
        },
        mounted() {
            this.test();
        },
        // 在created实现完全初始化之前
        setup(props,context) {
            return {
                name: '你好,强',
                handleClick: () => {
                    alert('真TM强')
                }
            }
        }   
    })
    const vm = app.mount('#root')
</script>

1.ref和reactive响应式引用的原理

  • ref:将普通的变量改变成为响应式的变量
    • ref处理基础类型的数据
    • 通过porxy对数据进行封装,当数据放生改变时候触发模板等内容的更新
<script>
    const app = Vue.createApp({
        template: `
        <div @click="handleClick">{{name}}</div>
        `,
        // 在created实现完全初始化之前
        setup(props,context) {
            const { ref } = Vue;
            // porxy,'你好强'在底层调用的时候会proxy({value: '你好强'}),这样的一个响应式引用
            let name = '你好强';
            setTimeout*(()=>{
                name.value = '太TM强了'
            },2000)
            return {name}
        }   
    })
    const vm = app.mount('#root')
</script>
  • reactive:非基础数据就可以使用该字段去使用
<script>
    const app = Vue.createApp({
        template: `
        <div>{{nameobj[0]}}</div>
        `,
        // 在created实现完全初始化之前
        setup(props,context) {
            const {reactive} = Vue
            const nameobj = reactive(['太TMD强了']);
            setTimeout(()=> {
                nameobj[0] = "强到爆炸"
            },2000)
            return {nameobj}
        }
    })
    const vm = app.mount('#root')
</script>
  • readonly:对响应式的进行限制被处理后的返回的响应式对象是不可以被修改的
  • toRefs:把一个reactive的对象转化为ref对象的形式

    • toRefs proxy({name:'你好强'}) => {name:proxy({value:'你好强})}
    • 模板中的返回的结构数据不具备响应式但是可以使用本函数包装成响应式
  • attrs:当父组件传递变量给子组件时候不需要用prom去接收

  • emit:可以子组件向外触发事件
<script>
    const app = Vue.createApp({
        template: `
        <child @change="handleChange">你是真的强</child>
        `,
        methods: {
            handleChange(){
                alert('change');
            }
        },
    })
    app.component('child',{
        template: `
        <button @click="handleClick">触发事件</button>
        `,
        setup(props,context) {
            const { h } = Vue
            const { atters,slots,emit } = context
            console.log(slots)
            //return () => h('div',{},slots.default())
            function handleClick() {emit('change');}
            return { handleClick }
        }
    })
    const vm = app.mount('#root') 
</script>

2.简单的开发todolist

  • 使用composeitionAPI的方法去实现简单的todolist
<script>
    // 单独封装list的信息
    const listRelativeEffect= () => {
        const { reactive } = Vue;
        const list = reactive([]);
        const addItemToList = (item) => {
            list.push(item);
        }
        return { list,addItemToList }
    };
    // 对inputValue内容进行封装
    const inputRelativeEffect = () => {
        const { ref } = Vue;
        const inputValue = ref('')
        const handleInputValueChange = (e) => {
            inputValue.value = e.target.value;
        }
        return { inputValue,handleInputValueChange }
    }

    const app = Vue.createApp({
        setup() {
            // 流程调度的中转
            const { list,addItemToList } = listRelativeEffect();
            const { inputValue,handleInputValueChange } = inputRelativeEffect();
            return {
                    list,
                    addItemToList,
                    inputValue,
                    handleInputValueChange,
            }
        },
        template: `
        <div>
            <div>
                <input :value="inputValue" @input="handleInputValueChange"/>
                <div>{{inputValue}}</div>
                <button @click="() => addItemToList(inputValue)">提交</button>
            </div>
            <ul>
                <li v-for="(item,value) in list" :key="value">{{item}}</li>    
            </ul>
        </div>
        `
    })
    const vm = app.mount('#root')
</script>

3.computed方法生成计算属性

  • ref的例子
<script>
    // comuted 的计算属性
    const app = Vue.createApp({
        setup() {
            const { ref,computed } =Vue;
            const count = ref(0);
            const handleClick = () => {
                count.value += 1;
            }
            let countaddFive = computed({
                get: () => {
                    return count.value + 5;
                },
                set: (parms) => {
                    return count.value = parms-10;
                }
            })
            setTimeout(() => {
                countaddFive.value = 100
            },1000)
            return {
                count,
                handleClick,
                countaddFive,
            }
        },
        template: `
        <div>
            <span @click="handleClick">{{count}}</span> -->{{countaddFive}}
        </div>
        `
    })
    const vm = app.mount('#root')
</script>
  • reactive用法
<script>
    // comuted 的计算属性
    const app = Vue.createApp({
        setup() {
            const { reactive,computed } =Vue;
            const countobj = reactive({count: 1});
            const handleClick = () => {
                countobj.count += 1;
            }
            let countaddFive = computed({
                get: () => {
                    return countobj.count + 5;
                },
                set: (parms) => {
                    return countobj.count = parms-10;
                }
            })
            setTimeout(() => {
                countaddFive.value = 100
            },1000)
            return {
                countobj,
                handleClick,
                countaddFive,
            }
        },
        template: `
        <div>
            <span @click="handleClick">{{countobj.count}}</span> -->{{countaddFive}}
        </div>
        `
    })
    const vm = app.mount('#root')
</script>

4.侦听器的用法

  • watch特性:懒惰性(变化的时候才会去执行),参数可以获取原始和当前的值
    • 支持监听多个数据的变化用函数数组返回,注意返回数据也是数组
    • watch还支持高级的方式比如immediate:true立刻变成非惰性监听
<script>
    const app = Vue.createApp({
        setup() {
          const { reactive,toRefs,watch } = Vue;
          const nameobj = reactive({name:"真TM强",englishName:"淦"})
          const { name,englishName } = toRefs(nameobj)
          watch([()=>nameobj.name,()=>nameobj.englishName],([ctValue,lValue],[preValue,plValue])=>{
              console.log(ctValue,preValue,'===>',lValue,plValue)
          })
          return {name,englishName}
        },
        template: `
        <div>
            <div>
                Name:<input v-model="name" />    
            </div>    
            <div>
                Name is {{name}}    
            </div>
        </div>
        <div>
            <div>
                Name:<input v-model="englishName" />    
            </div>    
            <div>
                Name is {{englishName}}    
            </div>
        </div>
        `
    })
    const vm = app.mount("#root")
</script>
  • watchEffect:立即执行的函数,非惰性执行
    • 代码中对内部有依赖则执行
    • 不需要传递你要监听的内容,它会自动的去监听
    • 不需要传递很多的参数,只需要传递一个回调函数
    • 不能获取之前数据的值
    • 异步操作相关的内容
<script>
    const app = Vue.createApp({
        setup() {
          const { reactive,toRefs,watch,watchEffect } = Vue;
          const nameobj = reactive({name:"真TM强",englishName:"淦"})
          const { name,englishName } = toRefs(nameobj)
          const stopwtch = watchEffect (()=>{
              console.log(nameobj.name)
              console.log(nameobj.englishName)
              setTimeout(()=>{
                  stopwtch() 
              },3000)
          })
          return {name,englishName}
        },
        template: `
        <div>
            <div>
                Name:<input v-model="name" />    
            </div>    
            <div>
                Name is {{name}}    
            </div>
        </div>
        <div>
            <div>
                Name:<input v-model="englishName" />    
            </div>    
            <div>
                Name is {{englishName}}    
            </div>
        </div>
        `
    })
    const vm = app.mount("#root")
</script>

5.新版生命周期函数的写法

  • 在setup函数中可以使用生命周期函数
    • onBeforeMount:指当我们的实例即将挂载到页面上的时候,等价于beforemount
    • onMounted:当页面挂载的时候等价于Monted
    • onBeforeUpdate:数据发生变化重新渲染的时候
    • onUpdate:数据发生修改完之后执行
    • onBeforeUnmount:当页面中的组件即将移除的时候执行
    • onUnmounted:当组件从页面中完全移除的时候执行
    • setup的生命时间点就是在Beforecreate和created之间所以不提供这个两个
    • onRenderTracked:每次渲染后收集依赖会执行函数
    • onRenderTriggered:每次重新渲染被重新触发的时候执行
<script>
    const app = Vue.createApp({
        setup() {
          const { onBeforeMount,reactive,ref,onMounted,onBeforeUpdate,onUpdated,
            onBeforeUnmount,
            onUnmounted,
            onRenderTracked, 
            onRenderTriggered,  
        } = Vue;
          const obj = reactive({name:'牛逼',show: true})
          onBeforeMount(()=> {
              console.log("onBeforeMount")
          })
          onMounted(()=> {
              console.log('onMounted')
          })
          onBeforeUpdate(() => {
              console.log('onBeforeUpdate')
          })
          onBeforeUnmount(() => {
              console.log('onBeforeUnmount')
          })
          onUnmounted(() => {
            console.log('onUnmounted')
          })
          onRenderTracked(()=>{
            console.log('onRenderTracked')
          })
          onRenderTriggered(()=>{
            console.log('onRenderTriggered')
          })
          const handleClick = () => {
              obj.name = '好强'
              obj.show = false
              console.log(obj.show)
          }
          return {obj,handleClick}
        },
        template: `
        <div>
            <div @click="handleClick">
                {{obj.name}} 
            </div>    
            <child v-if="obj.show" />
        </div>
        `
    })
    app.component('child',{
        template: `
        <div>测试用例好强</div>
        `
    })
    const vm = app.mount("#root")
</script>

4.provide/inject模板Ref用法inject

  • provide/inject在setup中的使用可以给孙子组件提供变量参数
  • 父子组件在使用的时候尽量单向数据流的方式.子组件的改变最好是调用父组件的
<script>
    const app = Vue.createApp({
        setup() {
          const { provide,ref,readonly } = Vue
          const text = ref("好强")
          provide("text",readonly(text))
          provide('change',(value)=>{
              text.value = value;
          })
          return {text}
        },
        template: `
        <div>   
            <div>
                <input v-model="text"/>    
            </div>
            <child  />
        </div>
        `
    })
    app.component('child',{
        setup() {
            const { inject }=Vue
            const name = inject('text','hello')
            const change = inject('change')
            const handleClick = ()=> {
                change('asd')
            }
            return {name,handleClick}
        },
        template: `
        <div @click="handleClick">{{name}}</div>
        `
    })
    const vm = app.mount("#root")
</script>
  • 通过ref获取真实的DOM元素节点
<script>
    const app = Vue.createApp({
        setup() {
            const { ref,onMounted }= Vue
            const hello = ref(null)
            onMounted(()=> {
                console.log(hello.value)
            })
            return {hello}
        },
        template: `
        <div>
            <div ref="hello">
                hello everyday
            </div>
        </div>
        `
    })
    const vm = app.mount("#root")
</script>

发表评论