- Vue3 中文文档(新) Vue.js - 渐进式 JavaScript 框架 | Vue.js
vue3的优点:
- 首次渲染更快
- diff 算法更快
- 内存占用更少
- 打包体积更小
- 更好的 Typescript 支持
- Composition API组合 API
首先理解一下vite 构建工具:
vite是一种新型前端构建工具,能够显著提升前端开发体验。
对比 webpack:
- webpack需要查找依赖,打包所有的模块,然后才能提供服务,更新速度会随着代码体积增加越来越慢
而vite 的原理是:
- 使用原生 ESModule 通过 script 标签动态导入,访问页面的时候加载到对应模块编译并响应
 基于 webpack 构建项目  与  基于 vite 构建项目,谁更快体验更好?vite
基于 webpack 的 vue-cli 也可以创建 vue 项目,只是慢一点而已。

6.进入项目目录,安装依赖,启动项目即可。npm i pnpm run dev或npm run dev启动项目
Vue3提供两种组织代码逻辑的写法:
- 通过data、methods、watch 等配置选项组织代码逻辑是选项式API写法
- 所有逻辑在setup函数中,使用 ref、watch 等函数组织代码是组合式API写法
一、组合式api
- 在setup中通过vue提供的函数组织代码实现功能,就是组合式API写法。
- 组合式API的好处:可复用,可维护
- ref 就是一个组合式API
二、生命周期函数
Vue2和Vue3生命周期对比

三、Vue3常用核心语法
1.setup函数
特点:
(1)setup函数是vue的特有选项,是组合式api的入口函数
(2)从生命周期看,它在beforeCreate之前执行
(3)作为入口函数,必须要有return
(4)没有this值
注:setup 中返回的对象数据不是响应式的,需要使用ref和reactive转成响应式
代码示例:
<template>
  <div>
   ===vue3
   ===={{ num }}
   ===={{ obj.age }}==={{ obj.name }}
   <button @click="btn">按钮</button>
  </div>
 </template>
 <script>
 import {ref,reactive} from 'vue'
    export default {
      name:'',
      setup(){
        //  ref定义响应式数据,不限数据类型 更改数据需要.value
       let num=ref(10)
      //  reactive定义响应式数据,只限于复杂数据类型  更改数据不需要.value
       let obj=reactive({age:12,name:'jack'})  
       
       const btn=()=>{
         num.value+=2
         obj.age=18
         obj.name='rose'
         console.log(num.value,obj.age,obj.name,99);
      }
      return {num,obj,btn}
    }
  }  
 </script>
 <style lang='less'  scoped>
  
 </style>2.setup语法糖:
作用:简化 setup 固定代码 ,让代码更简洁
使用:
(1)直接在script标签里面写setup 不用return 和 export default
(2)导入组件之后可以直接使用,不用注册
代码示例:
<template>
  <div>
    ===vue3
    ===={{ num }}
    ===={{ obj.age }}==={{ obj.name }}
    <button @click="btn">按钮</button>
  </div>
</template>
<script setup>
// setup写在script标签上就是语法糖,优化代码,不需要导入导出,在导入组件的时候也不需要注册
import { ref, reactive } from 'vue'
//  ref定义响应式数据,不限数据类型 更改数据需要.value
let num = ref(10)
//  reactive定义响应式数据,只限于复杂数据类型  更改数据不需要.value
let obj = reactive({ age: 12, name: 'jack' })
const btn = () => {
  num.value += 2
  obj.age = 18
  obj.name = 'rose'
  console.log(num.value, obj.age, obj.name, 99);
}
</script>
<style lang='less'  scoped>
</style>3.ref函数
作用:
(1)定义响应式数据,所有数据类型都可以使用(除复杂数据类型外,其他数据类型常用ref( ) )
使用步骤:
1.从vue中导入ref
2.在 setup 函数中,使用 ref 函数,传入数据,返回一个响应式数据
3.使用 ref 创建的数据,js 中需要 .value来取值 ,template模板 中可省略
(2)获取DOM元素,相当于Vue2中的自定义指令
使用步骤:
1.从vue中导入ref
2.模板中建立关联: ref="自定义属性名"
3.使用: 自定义属性名.value
代码示例:
<script setup>
  // 常用的 onMounted 组件渲染完毕:发请求,操作dom,初始化图表...
  import {ref, onMounted } from "vue";
  // 生命周期函数:组件渲染完毕
  onMounted(()=>{
    console.log('onMounted触发了')
    console.log(dom,'dom111');
  })
  // 默认值是null,需要在渲染完毕后访问DOM属性。
  let dom=ref(null)
  const btn=()=>{
    console.log(dom.value,'dom222');
  }
</script>
<template>
  <div>生命周期函数
    <h1 ref="dom">我是标题h1</h1>
    <button @click="btn">按钮操作dom</button>
  </div>
</template>4.reactive函数
作用:定义复杂数据类型的响应式数据,不能定义简单数据类型
使用步骤:
1.从vue中导入 reactive
2.在 setup 函数中,使用 reactive 函数,传入复杂数据类型数据,返回一个响应式数据
3.使用 reactive 创建的数据,js 和 template 模板中都可以直接使用
5.computed函数
作用:计算属性
使用步骤:
1.从vue中导入 computed
2.在 setup 函数中,使用 computed 函数,参数是一个函数,函数返回计算好的数据
3.计算好的数据在 js 中需要.value取值,template 模板中可以直接使用
代码示例:
<script setup >
    import {ref,reactive,computed} from 'vue'
    let arr=reactive([1,2,3,4,5])
    let val=ref(1)
    // computed动态求和 这里数组发生改变,computed计算属性就会触发  
    const total=computed(()=>{
     return arr.reduce((sum,item)=> sum+Number(item) ,0)
    })
    const handel=()=>{
        arr.push(val.value)
    }
</script>
<template>
 <div>
  御剑乘风来,除魔天地间!===vue3
  ======{{ total }}======={{ arr }}
  <input type="text" @blur="handel" v-model="val" placeholder="请输入数字">
 </div>
</template>
<style lang='less'  scoped>
    
</style>6.watch函数
作用:监听数据的变化
使用步骤:
1.从vue中导入 watch
2.在 setup 函数中,使用 watch 函数,参数有以下几种情况:
(1)监听简单数据类型,参数为:值,(newVal,oldVal)=> { } ,配置项
(2)监听复杂数据类型,参数为:值,(newVal)=> { } ,配置项
(3)监听对象中某个属性,参数为:()=>对象.属性,(newVal,oldVal)=> { } ,配置项
(4)同时监听多个数据,参数为:[数据1,数据2...],(newVal,oldVal)=> { } ,配置项
代码示例:
(1)监听简单数据类型
    // watch(需要监听的数据||函数,数据改变执行函数,配置对象) 来进行数据的侦听
    // 1 使用 watch 监听一个简单数据类型
    import {ref,watch } from 'vue'
    let num=ref(0)
   
    // setTimeout只执行一次
    setTimeout(()=>{
      num.value++
    },1000)
    // 监听num的变化
    watch(num,(nerval,olduvai)=>{
      console.log(nerval,olduvai,'num发生改变了');
    })(2)监听复杂数据类型
     // 2 使用 watch 监听响应式对象数据中的一个属性(简单)
    import {reactive,watch } from 'vue'
    let obj=reactive({age:18,name:'jack'})
   
   const btn=()=>{
    obj.age+=2
    obj.name='rose'
   }
    // 监听obj的变化 ,监听复杂数据类型的时候,只有新值newVal,没有旧值oldVal
  watch(obj,(newVal)=>{
    console.log(obj,newVal);
  })(3)监听对象中某个属性
    //3 使用 watch 监听响应式对象数据中的一个属性(监听复杂数据类型)
    import { reactive, watch } from "vue";
  const obj = reactive({
    num: 33,
    info: {
      name: "jack",
      age: 18,
    },
  });
   const btn=()=>{
    obj.num+=10
    obj.info.age+=2
    obj.info.name='rose'
   }
  watch(()=>obj.info.age,(newVal,oldVal)=>{
      console.log(obj.info.age,obj.info.name,newVal,oldVal);
  })(4)同时监听多个数据
// 4 使用 watch 监听多个数据
    import {ref,reactive,watch } from 'vue'
    let num=ref(1)
    let obj=reactive({age:18,name:'jack'})
   
   const btn=()=>{
    num.value+=1
    obj.age+=2
    obj.name='rose'
   }
    // 同时监听多个数据类型 newVal是一个数组
  watch([()=>obj.age,num],(newVal,oldVal)=>{
    console.log('111',newVal,oldVal);
  })7.ref操作组件-defineExpose函数
 作用:使用 <script setup> 的组件是默认关闭的,组件实例使用不到顶层的数据和函数。通过defineExpose函数可以将子组件中的数据和方法暴露出去,父组件直接通过ref就能调用子组件中的数据和方法
使用步骤:
1.子组件: defineExpose({变量名,函数名,... })
2.父组件: ref名.value.xxx 直接调用

8.父传子-defineProps函数 
 作用:实现父传子组件通讯
使用步骤:
1.父组件:和vue2语法一样正常传值
2.子组件:用defineProps接收
3.在js中,通过defineProps的返回值来接收使用数据,template 模板中可以直接使用
 9.子传父-defineEmits函数
  作用:实现子传父组件通讯
使用步骤:
1.子组件:
通过defineEmits声明事件名称,并接收返回值emit
根据条件触发emit('事件名称','传值'),进行传值
2.父组件:
模板中接收@事件名="新函数"
js中新函数可以通过参数e,接收传值

 10.跨级组件通讯provide与inject函数
 作用:通过provide和inject函数实现简单的跨级组件通讯
使用步骤:
1.祖先组件
(1)从 vue 中导出 provide 函数
(2)provide('变量名', 变量值);
2.子/孙组件
(1)从 vue 中导出 inject 函数
(2)const value = inject('变量名')
Q:如何通过provide和inject实现响应式数据传值?
 1.祖先组件先传变量和函数给子/孙组件
 2.子/孙组件接收函数并调用传值
 3.祖先组件中的函数接收传值,并对变量重新赋值 
父组件示例代码:
<script setup>
// provide和inject是解决跨级组件通讯的方案
// provide 提供后代组件需要依赖的数据或函数
// inject 注入(获取)provide提供的数据或函数
import Son03 from "./components/Son03.vue";
import { ref, reactive, provide } from 'vue';
const count = ref(100)
const obj = reactive({ age: 18, name: '小花' })
const addFn = (e) => {
  obj.name = e
  console.log(e);
}
// provide 提供后代组件需要依赖的数据或函数
// provide(键,值)  传值
provide('newCount', count.value)  //祖先组件向子组件和sun组件传值
provide('newObj', obj)
provide('newAddFn', addFn)
</script>
<template>
  <div>
    <h3>我是父组件===vue3</h3>
    <div>余额:{{ count }}元</div>
    <div>姓名:{{ obj.name }}</div>
    <hr />
    <Son03></Son03>
  </div>
</template>
<style lang='less'  scoped>
</style>子组件示例代码:
<script setup >
// 导入sun组件 
import sun from "./sun.vue";
 
</script>
<template>
  <div>
    <div>我是子组件===Son03</div>
    <hr />
    <sun></sun>
  </div>
</template>
<style lang='less'  scoped>
</style>孙组件示例代码:
<script setup >
// 跨级sun组件接收爷爷传过来的值count和obj  addFn函数
import { inject } from 'vue';
let newCount = inject('newCount')
let newObj = inject('newObj')
let newAddFn = inject('newAddFn')
console.log(newCount, 111);
console.log(newObj, 222);
console.log(newAddFn, 333);
const btn = (e) => {
  console.log(e, 444);
  newAddFn('小红')
}
</script>
<template>
  <div>
    <div>我是sun组件===sun</div>
    <div>{{ newCount }}</div>
    <div>{{ newObj }}</div>
    <div>{{ newAddFn }}</div>
    <button @click="btn">按钮</button>
  </div>
</template>
<style lang='less'  scoped>
</style>11.保持响应式 toRefs函数
 作用:在使用reactive创建的响应式数据被展开或解构的时候使用toRefs保持响应式
使用步骤:
1.从 vue 中导出 toRefs 函数
2.将被展开或解构的数据作为参数传入toRefs 函数
3.解构后的数据是一个变量,依然可以保持响应式,但js中需要通过.value取值,模板中不用
  
<script setup >
  import {reactive, toRefs} from 'vue'
  // 当去解构和展开响应式数据对象使用 toRefs 保持响应式
    const user =reactive({name:'tom',age:'18',gender:'男'})
    // const {name,age,gender}=user  //这种解构的写法 响应式失效
    const {name,age,gender}=toRefs(user)  //在解构对象的时候 使用了toRefs 才能保持数据是响应式的
  const btn=()=>{
    user.name='rose'
    user.age=28
    user.gender='女'
  }
</script>
<template>
 <div>
  御剑乘风来,除魔天地间!===vue3
      <!-- ===姓名:{{user.name}}===年龄:{{ user.age }}===性别:{{ user.gender }} -->
      ===姓名:{{name}}===年龄:{{ age }}===性别:{{ gender }}
      <button @click="btn">改变数据按钮</button>
 </div>
</template>
<style lang='less'  scoped>
    
</style>


















