VUE 3.0 初体验之路

码文不易啊,转载请带上本文链接呀,感谢感谢 https://www.cnblogs.com/echoyya/p/14394057.html


在2020年9月中旬,vue.js发布了3.0正式版,在不久的将来,VUE3.0 也终将成为大前端的必然趋势,

环境搭建

  1. node 版本要求: Node.js8.9 或更高版本 ,输入 node -v 查看node版本

  2. vue-cli 版本:达到 vue-cli4.5.0 以上,可创建vue3.0的项目,支持体验vue3.0的新特性,(3.x Preview),vue -V 查看脚手架版本

  3. 终端输入: vue create project_name

核心知识


一、组件的定义和使用

组件:是维护单一功能,可复用的单个个体,相同的样式及逻辑即可抽离成组件,方便维护,复用性增强。也是vue3.0项目中,最核心的概念

defineComponent:vue3.0中提供了一个函数返回传递给它的对象,最重要的是:在TypeScript下,给予了组件 正确的参数类型推断 。此处先不展开介绍,后续会总结 vue3.0 + ts。

setup:组件的启动函数,两个参数: props(父组件传递的数据)content ( 上下文对象),最后return 定义的数据,方法,钩子函数等,且setup中 没有this,不能访问this

<script>

    import { defineComponent } from 'vue'
    
    export default defineComponent ({
      setup (props, content) {
        // TODO 数据,方法,钩子函数等
        return { }
      }
    })

</script>

二、数据的定义和使用

  1. ref定义单个数据,接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value
import { ref } from 'vue'

export default {
  setup () {
    let num1 =  ref(10)  // Number
    let name1 =  ref('Echoyya')  // String
    let arr1 =  ref(['a','d','c','d'])  // Array 
    let obj1 =  ref({age:20})  // Object 

    // 获取及改变 ref对象的值,获取内部值的单一属性 value
    console.log(num1.value) // 10

    num1.value++
    console.log(num1.value) // 11
    
    return {
      //使用 ref 定义的数据,需要直接 return
      num1,name1,arr1,obj1
    }
  }
}

  1. reactive: 用于创建响应式数据,接收一个普通对象然后返回该普通对象的响应式代理,即双向数据绑定,
    • 使用 reactive 定义的数据,不需要逐一 return,可以使用 ES6 的扩展运算符。

    • 解构会破坏双向数据绑定的特性, 变更为单向数据绑定

    • 解决:vue3.0中添加了新特性,可对当前的数据进行转换。将其转换为响应式数据,toRefs将数据包裹即可转换为响应式数据

import { reactive, toRefs } from 'vue'

export default {
  setup () {
    let data = reactive ({
      num:33,
      arr:['a','d','c','d'],
      obj:{age:20},
    })
     // 获取及改变:reactive 定义的数据,调用时直接 reactive变量名.数据名,
    console.log(data.num) // 33

    data.num++
    console.log(data.num) // 34
    
    return {
      ...toRefs(data) 
    }
  }
}

三、方法的定义和使用

创建的方法仍然需要 return

<template>
  <div>
    <p><button @click="clickNum">{{num}}</button></p>
    <p><button @click="clickNum1">{{num1}}</button></p>
    <p><button @click="singleMethod">{{name}}</button></p>
  </div>
</template>

<script>

import { reactive, ref, toRefs } from 'vue'
export default {
  setup () {
    let num1 =  ref(10)
    let name =  ref('Echoyya')
    let data = reactive({
      num:33,
    })

    // 定义多个方法,不需要逐一 return
    let methods  = {
      clickNum1: () => {
        num1.value++ 
        console.log(num1.value);
      },
      clickNum : () => {
        data.num ++ 
        console.log(data.num);
      }
    }
     // 定义单个方法,需要return
    let singleMethod = () => {
      console.log(name.value)
    }
    return {
      num1,
      name,
      singleMethod,
      ...toRefs(data)
      ...methods,
    }
  }
}

</script>

四、路由的定义、使用和传参

  1. /src/router/index.js:在路由文件中使用了createRouter方法
import { createRouter } from 'vue-router'
const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('../views/Home.vue')
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  }
]
const router = createRouter({
  routes
})

export default router

  1. home组件中使用,路由跳转及传递参数
<template>
  <div>
    <p><button @click="gotoQuery">query跳转</button></p>
    <p><button @click="gotoParams">params跳转</button></p>
  </div>
</template>

<script>

import { useRouter } from 'vue-router'
export default {
  setup (){
    // router对象是全局路由的实例。
    let router = useRouter()

    // 跳转路由用push: 跳转时可使用name 和 path,传递参数可使用query 和 params

    let gotoQuery = () => {
      // query: 可以使用name和path,参数显示在地址栏中, 且页面刷新参数仍在
      router.push({
        // name:'About',
        path:'/about',
        query:{
          name:'Echoyya',
          age: 25,
          obj:JSON.stringify({gender:"f"})
        },
      })
    }
    let gotoParams = () => {
       // params:只能使用name ,不显示在地址栏中,且页面刷新,参数清空 console.log(route.params); 打印空对象
       router.push({
        name:'Home',
        params:{
          name:'Echoyya',
          age: 25,
          obj:JSON.stringify({gender:"f"})
        }
      })
    }

    return {
      gotoQuery,
      gotoParams
    }
  }
}
  1. about组件中使用,接收路由参数
import { useRoute } from 'vue-router'
export default {
  setup (){
    // route对象表示当前的路由信息,包含了当前 URL 解析得到的信息。包含当前的路径,参数,query对象等。
    let route = useRoute() 
    
    console.log(typeof route.query.age) //string, query传递的参数都是string类型
    console.log(route.query);    //获取query传参
    console.log(route.params);    //获取params传参
    return {}
  }
}

五、父子组件传值

  1. 父 to 子:通过动态绑定属性的方式,子组件在props 中去接收,

  2. 子 to 父:通过ctx.emit('事件名称', 传递的参数)事件分发的方式, 父组件当中,调用子组件标签上绑定自定义事件,其中包含一个参数,即子组件传递过来的数据

    • ctx.emit('事件名称', 传递的参数)事件分发, ctx是 setup 函数的第二个参数,上下文对象

    • emit 只能接受两个参数,其余不生效,第一个参数:事件名称,第二个: 传递的数据

    • 事件分发,不一定要通过点击事件,也可使用钩子函数等

    • 需要传递多个参数时,emit第二个参数可选择数组或是对象

father.vue

<template>
  <div class="wrapper">
    <p>this is father components</p>
    <p> 子组件传递的值:{{childMsg}}</p>
    <!-- msg 自定义属性,send 自定义监听事件-->
    <p><child :msg="msg" @send="getChildData"></child></p>
  </div>
</template>

<script>
import { ref } from 'vue'
import child from '../components/child'
export default {
  components:{
    child
  },
  setup() {
    let msg = ref('father组件数据')
    let childMsg = ref('')
    let getChildData = (data)=>{
      childMsg.value = data
    }
    return {
      msg,
      childMsg,
      getChildData
    }
  },
}
</script>

child.vue

<template>
  <div>
    this is child components
    <p>父组件传递过来的值:{{msg}}</p>
    <p><button @click="send">传值给父组件</button></p>
  </div>
</template>

<script>
import {ref,onMounted, reactive} from  'vue'
export default {
  name:'child',
  // props 接收的数据,不能直接修改,如props.xxx = yy
  props:{
    msg:{
      type:String , // 数据类型校验
      require:true ,  // 是否必传 默认false
      default:'默认值' // require和default 有些冲突,即必填时,可不设置默认值
    }
  },
  setup(props,ctx){
    console.log(props.msg);   // 父组件传递的数据:father组件数据

    let childMsg = ref('child组件数据')
    let data = reactive({
      childNum:10
    })
    
    let send = ()=>{
       ctx.emit('send',childMsg.value)
       // ctx.emit('send',[childMsg.value,data.childNum])  // 数组
       // ctx.emit('send',{  // 对象
       //   msg:childMsg.value,
       //   num:data.childNum
      })  
    }
    return {
     childMsg,
     send,
     ...data
    }
  }
})
</script>

六、状态管理的定义和使用

状态管理即 VUEX,为达到数据共享的目的

  1. /src/store/index.js:在状态管理文件中使用了createStore方法
import { createStore } from 'vuex'

export default createStore({
  // 定义所需要的状态
  state: {
    name: 'Echoyya',
  },

  // 同步修改state ,是方法,不能操作异步操作(包括发送请求及定时器等)
  mutations: {
    // 可接收两个参数:一:state,二:需修改的值,payload(可选)
    setName(state, payload) {
      state.name = payload
    },
  },
  // 提交 mutations
  actions: {
    // 可接收两个参数 一:store, 二 要修改的值
    asyncSetName(store, params) {
      setTimeout(() => {
        // commit 是提交mutation, 提交异步的mutations方法
        store.commit('setName', params)
        console.log(store.state.name) 
      }, 2000)
    }
  },
  // 模块化
  modules: {}
})

  1. 组件中调用,VUEX操作数据
<template>
  <div>
    {{name}}===={{name1}}===={{name2}}
    <p><button @click="setName">设置 name</button></p>
    <p><button @click="asyncSetName">异步设置 name</button></p>
  </div>
</template>

<script>
import { reactive, ref, toRefs, computed } from 'vue'
import { useStore } from 'vuex'

export default {
  setup (){
    //通过 ref 方式
    let name = ref(store.state.name)
   
    // 计算属性 方式
    let name1 = computed(()=>{
      return store.state.name + 'computed'
    })
    
    //reactive 方式
    let data = reactive({
       name2:store.state.name + '_reactive'
    })
    
    // 触发 mutations
    let setName = ()=>{
       console.log(store.state.name)  // Echoyya
       store.commit('setName','nhyya') 
       console.log(store.state.name)  // nhyya
    }
    // 触发 action
    let asyncSetName = ()=>{
        store.dispatch('asyncSetName','nhyya1212') 
    }
    return {
      name,
      name1,
      ...toRefs(data),
      setName,
      asyncSetName
    }
  }
})
</script>

七、常用的生命周期

  1. setup:不需要引入的生命周期 ,表示组件创建的过程,且没有this

  2. onMounted:比setup 稍微晚一些执行,表示组件挂载的过程,包括数据, dom元素等,是一个函数,需要传入一个回调函数执行,无参数。

    • 常用于:发送请求、数据初始化的操作、接受路由传递的参数
  3. onUnmounted:与 onMounted 相对应,组件卸载或销毁(路由跳转),常用于清除定时器等操作

较 VUE2.0 另有哪些改变?

  • 3.0去掉了filter, 没有beforeCreate created,用setup取代

  • setup里没有this

  • 3.0兼容IE12以上

  • 可直接监听数组类型的数据变化

  • 监听的目标为对象本身,不需要像Object.defineProperty一样遍历每个属性,有一定的性能提升

  • 直接实现对象属性的新增/删除

  • 重构 Virtual DOM:模板编译时的优化,将一些静态节点编译成常量

  • 另附上vue3.0 文档地址: https://v3.cn.vuejs.org/

上述内容并非全部 VUE3 内容,只是我通过一段时间的学习,做的自我总结,以便学习和复习,写的不准确之处还望大神们能留言指正

posted @ 2021-02-09 20:01  Echoyya、  阅读(1351)  评论(2编辑  收藏  举报