Vue3系列

Vue系列文章目录


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:Vue2过渡到Vue3的写法

提示:以下是本篇文章正文内容,下面案例可供参考

Vue3

vue2的升级版本,做了一些内部优化,从性能上,还有写法上都有改变。还有就是对vue2做了兼容。

文档: https://cn.vuejs.org/

Vue3 新特性

数据双向绑定的原理改变了, 改成proxy (原来: Object.defineProperty() )
增加了setup函数 (以前都是选项式,现在呢就是可以支持hooks函数式)
增加了hooks函数
支持ts
支持jsx/tsx
性能有提高: 大概 1.2 - 2 倍
对vue2做了兼容(放弃了一些api)

开始vue3

感受一下setup

<template>
  <div class="home">
      {{num}}
      <div><button @click="add">add</button></div>
  </div>
</template>

<script>

// 导入一个创建响应式对象的hooks  ref
import { ref } from 'vue'
export default {
  name: 'HomeView',
  setup(){   // setup选项
    const num = ref(0);   // 创建一个响应式对象
    function add(){   // 定义的一个方法
      num.value++
    }
    return {  // 在setup函数里面,返回出去的东西,就可以外面使用了
      num,
      add
    }
  }
}
</script>

vscode的插件

Volar vue3的插件

Vetur vue2的插件

做vue3开发的时候,要把vue2的插件禁用。

setup函数

这是vue3里面新加的钩子

接收两个参数: props, context

可以返回一个对象,返回的这个对象就可以在外面调用了,比如: 数据,方法…

是在实例创建挂载前执行的。(在setup里面拿不到this; 里面要使用hooks去完成 )

reactive/shallowReactive

reactive:深层次的响应式对象,接受一个数据, 通常是复杂类型数据
shallowReactive::非深层次的响应式对象

<template>
  <div class="home">
    <div> {{ count.num }} </div>
    <div> <button @click="change">count++</button> </div>
    <hr/>
     user:{{user.name}} --{{ user.hobby.h1 }},{{ user.hobby.h2 }}
      <div>
        <button @click="changeName">changename</button>
        <button @click="changeHobby">改变爱好</button>
      </div>

      <hr/>

      obj: {{ obj.name}}--{{obj.hobby.h1}},{{obj.hobby.h2}}
      
      <div><button @click="changeObj">change obj</button></div>
  </div>
</template>

<script>
// 创建响应式对象
import { reactive, shallowReactive } from 'vue'; 

export default {
  name: 'HomeView',
  setup(){  
    // 深层次的响应式对象
    const count = reactive({num: 1})   // 接受一个数据, 通常是复杂类型数据
    // const count = {num:1}
    function change(){
      count.num++
      console.log(count)
    }

    // 非深层次的响应式对象 
    // 只有第一层数据发生改变,才会触发视图的更新
    const user = shallowReactive({
      name:'young',
      hobby:{
        h1: 'code',
        h2: 'sing'
      }
    })

    function changeName(){
      user.name = 'yyds'
    }

    function changeHobby(){
      user.hobby.h1 = 'jump';
      console.log(user)
    }

    const obj = reactive({
      name:'young',
      hobby:{
        h1: 'code',
        h2: 'sing'
      }
    })
    function changeObj(){
      obj.hobby.h1 = 'jump!!!'
    }

    return { 
      count ,
      change,

      user,
      changeName,
      changeHobby,

      obj,
      changeObj
    }
  }
}
</script>

ref

使用ref创建响应式独享,可以接收一个基本类型的数据
在js中访问到数据,要通过.value
在模板中可以直接取

<template>
  <h2>app</h2>
  <div>
    {{state}}
  </div>
  <div><button @click="add">count++</button></div>
</template>

<script>
  // ref 
  import { ref } from 'vue';
  export default {
    setup(){
      // 使用ref创建响应式独享,可以接收一个基本类型的数据
      // 在js中访问到数据,要通过.value
      // 在模板中可以直接取
      const state = ref(0)
      function add(){
        // state.value++
        // console.log(ref)
        state.value++
      }
      return {
        state,
        add
      }
    }
  }
</script>

toRefs

将数据转换成ref创建的数据

<template>
  <h2>app</h2>
  <div>
    state: {{state}}
  </div>
  <div>
    count: {{ count }}
  </div>
  <div>
    obj: {{count}}
  </div>
  <div>
    <button @click="add">count++</button>
    <button @click="add2">obj.count++</button>
  </div>
</template>

<script>
  import { ref, reactive, toRefs } from 'vue';
  export default {
    setup(){
      const state = ref(0)
      const count = reactive({count: 0})
      const obj = toRefs(count)   // 转换成ref

      function add(){
        count.count++
        // console.log(count)
      }
      function add2(){
        // obj.count++
        // console.log(obj)
        count.count++
      }
      return {
        state,
        add,
        ...count,    // 用扩展运算符展开后再返回的reactive对象就失去了响应式.
        ...obj,     // ref对象展开后返回,也还是有响应式的.
        add2
      }
    }
  }
</script>

isRef/isReactive

判断是否是一个由Ref/Reactive创建的数据

<template>
  <h2>app</h2>
  <div>
    state: {{state}}
  </div>
  <div>
    count: {{ count }}
  </div>
  <div>
    obj: {{obj.count}}
  </div>
  <div>
    <button @click="add">test</button>
    <button @click="add2">test2 </button>
  </div>
</template>

<script>
  import { ref, reactive, toRefs, isRef, isReactive } from 'vue';
  export default {
    setup(){
      const state = ref(0)
      const count = reactive({count: 0})

      const obj = toRefs(count)   // 转换成ref

      function add(){
        console.log(isRef(state))  // true
        console.log(isRef(count))  // false
        console.log(isRef(obj))    // false
      }

      function add2(){
        console.log(isReactive(state))   // false
        console.log(isReactive(count))   // true
        console.log(isReactive(obj))     // false
      }

      return {
        state,
        count,
        obj,
        add,
        add2
      }
    }
  }
</script>

readonly(只读)/shallowReadonly(表面只读)

设置数据为只读属性

<template>
  <h2>app</h2>
  <div>
    count: {{ count }}
  </div>
  <div>
    obj: {{obj}}
  </div>
  <div>
    couter:{{couter}}
  </div>
  <div>
    <button @click="add">test</button>
    <button @click="add2">test2</button>
  </div>
</template>

<script>
  import { reactive, readonly, shallowReadonly } from 'vue';
  export default {
    setup(){
     
      const count = reactive({count: 0, hobby:{ h1:'code'}})
      const obj = readonly(count)  // 所有层都不能改
      const couter = shallowReadonly(count)  // 第二层往后就可以改了
      function add(){
        //[Vue warn] Set operation on key "count" failed: target is readonly. 
        // 不能修改只读对象,修改会报警告
      //  obj.count++
        obj.hobby.h1 = 'sing'
      }
      return {  
        count,
        add,  
        obj,
        couter,
        add2(){
          // couter.count++
          couter.hobby.h1 = 'sing'
        }
      }
    }
  }
</script>

生命周期

在这里插入图片描述

链接:生命周期钩子

链接:生命周期选项

选项式生命周期钩子和,setup(hooks)生命周期钩子对比

选项式 APIHook inside setup
beforeCreateNot needed*
createdNot needed*
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered
//下面两个是keep-alive包裹的组件增加的两个生命周期钩子
activatedonActivated
deactivatedonDeactivated

setup就是之前vue2的选项都可以写在这里面.
对应的选项就有对应的hooks来去完成
包括生命周期钩子也是用到hooks来去做

<template>
  <h2>app</h2>
  <div>{{num}}</div>
</template>

<script>
  //  1. 导入生命周期钩子
  import { onMounted, ref } from 'vue';
  export default {
    setup(){
      // setup就是之前vue2的选项都可以写在这里面.
      // 对应的选项就有对应的hooks来去完成
      // 包括生命周期钩子也是用到hooks来去做

      let apphtml = document.getElementById('app').innerHTML;
      console.log(apphtml)

      const num = ref(99)

      // 2. 使用
      // 挂载后的生命周期钩子 onMounted
      // 需要接受一个函数, 这个生命周期钩子要执行的函数

      onMounted(()=>{  
        // console.log('挂载后')
        apphtml = document.getElementById('app').innerHTML;
        console.log(apphtml)
        console.log(num.value)
      })

      return {
        num
      }
    },
    
  }
</script>

计算属性

在Vue3中计算属性也变成了钩子

<template>
  <h2>app</h2>
  <div>num:{{num}}</div>
  <div>numCache:{{numCache}}</div>
  <div><button @click="changenum">修改num</button></div>
  <br />
  <hr />
</template>

<script>
  // 计算属性
  // 也变成了钩子
  import { ref, reactive, computed } from 'vue';
  export default {
    setup(){
      const num = ref(99)

      // 得到了一个计算属性
      // 1.回调函数
      const numCache = computed(()=>{
        console.log('aaaa')
        return num   // 当前计算属性的依赖
      })
      // 2.对象的形式
      // 传一个对象进来
      // get()  取值 的时候触发
      // set()  被设置值的时候触发
      const count = ref(0)
      // 可写的计算属性
      // 他的的返回值是一个ref类型的对象 
      let countPlus = computed({
        get:()=>{
          return count.value*2
        },
        set:(val)=>{  // countPlus.value 修改后就会触发这个set
          // console.log('countPlus修改了:'+val)
          count.value = val
        }
      })
      
      return {
        num,
        numCache,
        count,
        countPlus,
        changenum(){
          num.value++
        },
      }
    },
    
  }
</script>

侦听器

也是一个hooks, 有返回值,是一个函数,这个函数被执行了就停止监听了
两种情况:
监听一个值:
参数1:是一个回调函数 返回什么就监听那个值的变化
参数2: 是改变后要触发的函数, 有两个参数,修改后,前的值
监听多个值:
参数1: 就变成一个数组,里面的元素都是要监听的对象
参数2: 是改变后要触发的函数, 有两个参数,修改后,前的值

<template>
  <h2>app</h2>
  <div>num:{{num}}</div>
 
  <div><button @click="changenum">修改num</button></div>
  <br />
  <hr />

  <div>age:{{age}}</div>
  <div>score:{{score}}</div>
  <div>
    <button @click="changeage">changeage</button>
    <button @click="changescore">changescore</button>
  </div>

  <div>
    <button @click="stop">停止 age-score的监听</button>
  </div>
</template>

<script>
  // 侦听器
  import { ref, watch } from 'vue';
  export default {
    setup(){
      const num = ref(99)
      const age = ref(18)
      const score = ref(100)
      // 也是一个hooks

      // 适合监听一个值的情况
      // 参数1:是一个回调函数 返回什么就监听那个值的变化
      // 参数2: 是改变后要触发的函数, 有两个参数,修改后,前的值
      // 有返回值,是一个函数,这个函数被执行了就停止监听了
      watch(
        ()=>{
          return num.value
        },
        (newval,oldval)=>{ 
          console.log('num改变了')
          console.log(newval)
          console.log(oldval)
        }
      )

      // 监听多个值
      // 参数1: 就变成一个数组,里面的元素都是要监听的对象
      // 有返回值,是一个函数,这个函数被执行了就停止监听了
      const stopwatch = watch([score,age],(newval,oldval)=>{
        // console.log('num/age变化了')
        console.log(newval)   // 和参数1的顺序是对应的, 都是修改后的值
        console.log(oldval)   // 修改前的值 
      })

      return {
        num,
        age,
        score,
        changenum(){
          num.value++
        },
        changeage(){
          age.value++
          // score.value++
        },
        changescore(){
          score.value++
        },
        stop(){
          stopwatch()
        }
      }
    },
    
  }
</script>

setup语法(完全的Vue3写法)

只要给script加上 setup属性; 里面的代码就相当于写在setup里面
不需要return 了.
顶层变量就可以直接在外面用

<template>
  <h2>app</h2>
  <div>{{ num }}</div>

  <div> {{ a }} </div>
  <div> <button @click="changenum">change-num</button> </div>
</template>

<script setup>
  // 只要给script加上 setup属性; 里面的代码就相当于写在setup里面
  // 不需要return 了.
  // 顶层变量就可以直接在外面用
  import { ref, onMounted } from 'vue';
  const num = ref(0)

  function changenum(){
    num.value++
  }

  onMounted(()=>{
    console.log('aaaaaaaaaaaaaaaaa')
  })

  // {  
  //   const a = 10;   //不是顶层变量就不能在外面用.
  // }
  const a = 10;
</script>

provide/inject(依赖注入)

HomeView.vue

<template>
  <div>
    <div>home</div>
    <Parent></Parent>
  </div>
</template>
<!-- 当做是祖先组件 -->

<!-- 祖先向后代传值 -->
<script>
  /*
    home                     money
        Parent 
            Son                拿到money
  */ 
  import { provide } from 'vue';
  import Parent from './Parent.vue';
  export default {
    setup(){
      // 参数1: 传的名字
      // 参数2: 传的值
      provide('money',100)   // 定义向下传的值.
    },
    components: {
      Parent
    }
  }
</script>
Parent.vue

<template>
  <div>parent</div>
  <hr/>
  <Son></Son>
</template>

<script>
  import Son from './Son.vue'
  export default {
    components:{
      Son
    }
  }
</script>
Son.vue

<template>
  <div>
    son
  </div>
</template>
<script>
  import { inject } from 'vue';
  export default {
    setup(){
      const box = inject('money');   // 拿到传下来的值
      console.log(box)
    }
  }
</script>

router4.x

因为在setup里面没有this(this不代表当前实例), 不能使用this. r o u t e r / t h i s . router/ this. router/this.route 对象

所以就提供了对应的hooks来帮助我们拿到这两个对象

useRouter // 执行了可以返回一个路由对象 $router

useRoute // 返回一个路由信息对象

<template>
  <button @click="goabout">跳转到about</button>  
  <button @click="gomy">跳转到my</button> 

  <hr>

  <h2> count:  {{ this.$store.state.count }}</h2>
  <h2> {{ count }}  </h2>
  <button @click="getCount">获取到vuex -- count</button>
</template>
<script>
  import { computed } from 'vue';
  import { useRouter, useRoute } from 'vue-router';
  import { useStore, mapState } from 'vuex';
  export default {
    setup(){
      const $router = useRouter();
      
      const $store = useStore();
      // 在setup里面就不要使用辅助函数, 在这里没有优势,代码还比较复杂
      const count = computed(()=>$store.state.count)
      const aa = mapState(['age'])
      // 因为在sutup里面没有 this, 所以不能拿到我们要的属性值.
      console.log(aa.age)  // 100
      // console.log(aa.age.bind({$store:this.$store}))  // 以前的
      console.log(aa.age.bind({$store:$store})())  //现在要通过bind()改变

      return {
        count,
        goabout(){
          // 在setup中this不代表实例对象,所以就不能通过this.$router/ this.$route 获取到和路由相关的对象
          // 如果要获取就要使用vue-routert提供的hooks
          // this.$router.push('/about')
          // console.log(this)

          // useRouter()  获取路由对象  (可以操作)
          // useRoute() 获取到路由信息对象 (只有信息,  params query  ..)
          
          // console.log($router)
          // $router.push('/about')
          $router.push({name: 'about'})
        },
        gomy(){
          $router.push({
            name: 'my',
            params: {
              id: 1234
            },
            query: {
              age: 18,
              name: 'yyds'
            }
          })
        
          /*
          // 用path 跳转,不能传 params
          $router.push({
            path: '/my',
            params: {
              id: 1234
            },
            query: {
              age: 18,
              name: 'yyds'
            }
          })
          */
        },
      
      }
    }
  }
</script>
  

Vuex4

也是因为在setup中拿不到this, 所以也是通过hooks ,useStore(); 来拿到仓库对象

<template>
  <button @click="goabout">跳转到about</button>  
  <button @click="gomy">跳转到my</button> 

  <hr>

  <h2> count:  {{ this.$store.state.count }}</h2>
  <h2> {{ count }}  </h2>
  <button @click="getCount">获取到vuex -- count</button>
</template>
<script>
  import { computed } from 'vue';
  import { useRouter, useRoute } from 'vue-router';
  import { useStore, mapState } from 'vuex';
  export default {
    setup(){
      const $store = useStore();   
      // 在setup里面就不要使用辅助函数, 在这里没有优势,代码还比较复杂
      const count = computed(()=>$store.state.count)
      const aa = mapState(['age'])
      // 因为在sutup里面没有 this, 所以不能拿到我们要的属性值.
      console.log(aa.age)  // 100
      // console.log(aa.age.bind({$store:this.$store}))  // 以前的
      console.log(aa.age.bind({$store:$store})())  //现在要通过bind()改变

      return {
        count,
        getCount(){
         console.log($store.state.count) 
        }
      }
    }
  }
</script>

自定义指令

局部定义

在这里插入图片描述

全局定义

在这里插入图片描述

总结(连载中…)

提示:这里对文章进行总结:本文仅仅简单介绍了Vue3的使用,提供了大量能使我们快速便捷地处理数据的函数和方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

抬头第一眼,是天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值