VUE 3.0 初体验之路
码文不易啊,转载请带上本文链接呀,感谢感谢 https://www.cnblogs.com/echoyya/p/14394057.html
在2020年9月中旬,vue.js发布了3.0正式版,在不久的将来,VUE3.0 也终将成为大前端的必然趋势,
环境搭建
- 
node版本要求:Node.js8.9或更高版本 ,输入node -v查看node版本
- 
vue-cli版本:达到vue-cli4.5.0以上,可创建vue3.0的项目,支持体验vue3.0的新特性,(3.x Preview),vue -V查看脚手架版本
- 
终端输入: 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>
二、数据的定义和使用
- 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
    }
  }
}
- 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>
四、路由的定义、使用和传参
- /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
- 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
    }
  }
}
- 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 {}
  }
}
五、父子组件传值
- 
父 to 子:通过动态绑定属性的方式,子组件在props中去接收,
- 
子 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,为达到数据共享的目的
- /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: {}
})
- 组件中调用,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>
七、常用的生命周期
- 
setup:不需要引入的生命周期 ,表示组件创建的过程,且没有this 
- 
onMounted:比 setup稍微晚一些执行,表示组件挂载的过程,包括数据, dom元素等,是一个函数,需要传入一个回调函数执行,无参数。- 常用于:发送请求、数据初始化的操作、接受路由传递的参数
 
- 
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 内容,只是我通过一段时间的学习,做的自我总结,以便学习和复习,写的不准确之处还望大神们能留言指正

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号