首先创建vue3.0 项目

方法一: 命令行工具 (CLI)

查看@vue/cli版本 确保在4.5.0 以上 vue – version 或者 vue –v
下载@vue/cli  npm install –g @vue/cli
npm create 项目名

方法二:Vite

npm版本 6.x
npm init vite@latest <project-name> --template vue
npm版本 7+,需要加上额外的双短横线
npm init vite@latest <project-name> -- --template vue
cd <project-name>
npm install
npm run dev

若要创建vue3+Ts项目 则将上述template vue换成template vue-ts

相比于vue2的变化

1.模板中可以没有根标签

2.main.js中变化

vue2引入的是vue的构造函数
vue3引入名为createApp的工厂函数
vue3中实例对象app比vue2中vm‘轻’没有vm身上那么多的属性和方法

// vue2引入的是vue的构造函数
// import Vue from "vue";
// vue3引入名为createApp的工厂函数
import { createApp } from 'vue'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

import App from './App.vue'

// 创建应用实例对象app 
//(类似vue2中的vm,但app比vm‘轻’没有vm身上那么多的属性和方法)
const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

组合API

一、setup

1.作用

  1. setup是vue3.0中新的配置项 值为函数,是 Composition API(组合API)的入口
  2. vue3.0中新的配置项,值为函数,组件中所用到的数据和方法…配置在setup中
  3. 在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用

2.返回值

  • 第一种若返回一个对象,则对象中的属性,方法,在模板中均可以直接使用
  • 第二种若返回一个渲染函数可以自定义渲染内容(例如 return ()=>h(‘h1’,’你好’))

3.注意点

1、setup在beforeCreate 和 created 之前执行,this是undefind
2、由于在执行 setup函数的时候,还没有执行 Created 生命周期方法,所以在 setup 函数中,无法使用 data 和 methods 的变量和方法
3、由于我们不能在 setup函数中使用 data 和 methods,所以 Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined
4、setup函数只能是同步的不能是异步的
5、vue2配置的(data、methods、computed…)中可以访问到setup中的属性和方法
6、setup中不能访问到vue2配置的(data、methods、computed…)
7、如果有重名 setup优先
8、setup不能是一个async函数,因为返回值不再是return 对象,而是promise,模板看不到return

4.参数

setup有两个参数
参数1:props 值为对象,包含组件外部传递过来且组件内部声明接收了的属性(大白话就是:父传子通过props,子组件必须写props进行接收,这样setup的第一个参数才能使用)
参数2:上下文是一个普通 JavaScript 对象,暴露了其它可能在 setup 中有用的值

  • Context.attrs:值为对象,包含外部传递过来,但没有在props配置中声明的属性
  • Context.slots:收到的插槽内容 插槽用法如下:
父组件中:
<Childll>
  <template v-slot:vSlot8>
    <span>插槽练习</span>
  </template>
</Childll>
子组件中
<template>
<slot name="vSlot8"></slot>
</template>
  • Context.emit:分发自定义事件的函数,相当于vue2.X中的this.$emit

子组件:

<template>
  <div>
    <button @click="clickBtn" class="btn-item">hi~</button>
  </div>
</template>
<script>
export default {
  setup (props, context) {
    const clickBtn = () => {
      context.emit("on-change", "hi~");
    };
    return { clickBtn}
  }
</script>

父组件:

<template>
  <div>
    <Child @on-change="emitFn" />
  </div>
</template>

<script>
import Child from "./Child.vue"
export default {
  components: {
    EmitChild
  },
  setup () {
    const emitFn = v => {
      console.log(v);
    }
    return { emitFn }
  }
}
</script>

二、Ref函数

作用:定义响应式的数据
用法:

  1. 先引入ref import { ref } from ‘vue’;
  2. 定义数据: let username = ref(‘张三’) let job = ref({ type: ‘男’,age: 18})
  3. Js中操作定义的数据 username.value job.value.type
  4. 模板中读取数据 {{ username }} {{ job.type }}

三、reactive函数

作用:定义一个对象类型的响应式数据
用法:

  1. 先引入reactive import { reactive} from ‘vue’;
  2. 定义数据: let num= reactive ([1,2,3,4,5]) let job = ref({children: {type:‘男’,age: 18}})
  3. Js中操作定义的数据 num[0] job. children.type

四、Ref和Reactive的区别

  1. 定义数据:
    Ref用来定义基本数据类型、Reactive定义对象\数组类型数据
  2. 原理:
    Ref通过vue2中的Object.defineProperty()的get与set来实现响应式数据劫持
    Reactive通过使用Proxy来实现响应式
  3. 使用
    Ref定义数据后js中操作数据需要.value获取,模板读取不需要.value
    Reactive定义数据后 操作和读取均不需要.value

五、生命周期

写法一、跟vue2.X写法一样,区别在于(beforeUnmount、unmount)名称不一样
写法二、写在setup里面的生命周期,通过组合API的形式
使用均需要引入
如: import { onBeforeMount } from ‘vue’
Setup(){ onBeforeMount( () =>{} ) }
具体对比:

Vue2.XVue3.0
beforeCreate不需要(也可以理解为setup)
created不需要(也可以理解为setup)
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmount
activatedonActivated
deactivatedonDeactivated

六、Hook

Hook:是一个函数、把setup函数中的组合api进行了封装,类似于vue2中的mixin,
Src目录下新建hooks文件夹 里面写各种逻辑的hook
例如:新建usePoint.js

// 引入文件所需
import { reactive, onMounted, onBeforeUnmount } from 'vue'
export default function(){
  let point = reactive({
    x:0,
    y:0
  }), 
  function savepoint(event){
    point.x = event.pageX
    point.y = event.pageY
  }
  onMounted(() => {
    window.addEventListener('click',savepoint)
  })
  onBeforeUnmount(()=>{
    window.removeEventListener('click',savepoint)
  })
  return point
}

其他vue文件需要用到此hook时

import  usepoint  from  '路径'
// 然后在setup 中直接调用赋值
setup () {
	let point = usepoint()
	return {point}
}

七、toRef和torefs

有这么一个痛点
例:
定义一个英雄的对象,渲染时在模板中使用会重复数次写Hero.

<template>
  <p>姓名:{{Hero.name}}</p>
  <p>年龄:{{Hero.age}}</p>
  <p>技能:{{Hero.job.j1.speak}}</p>
</template>
<script>
import { reactive} from "vue";
export default {
setup() {
    let Hero = reactive({
      name: '李四',
      age: 18,
      job: {
        j1: {
          speak: '你好'
        }
      }
    })
    return {
      Hero
    }
  }
}
</script>

解决上述痛点:

toRef

作用:创建一个ref对象,或者可以说将一个不是ref的变为ref
用法: 1. 引入
import { toRef } from “vue”;
在这里插入图片描述
这样模板中就是可以直接使用{{name}}

toRefs

toRef一次只能处理一个属性而toRefs可以处理多个

import { toRefs } from "vue";
 setup() {
return {
     ...toRefs(Hero)
    }
}

这样就解决一开始的痛点在模板中多次书写Hero.

八、toRaw

  1. 将一个由reactive生成的响应式对象转为普通对象(ref生成的不行)
  2. 操作场景 用于读取响应式数据,后续操作不会引起页面数据变化
  3. 用法: toRaw(需要转换的对象的)

九、markRaw

  1. 标记一个对象永远不作为响应式对象
  2. 用法 markRaw(需要标记的对象)

十、customRef

创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显式控制,customRef里面需要写一个函数,函数接收两个参数,并且应该返回一个带有 get 和 set 的对象
track () 在get中通知vue追踪return出去的数据变化
tigger() 在set中改完数据后 通知vue重新解析模板

<template>
  <input v-model="keyword" />
  <h3>{{keyword}}</h3>
</template>

<script>
import { customRef } from "vue";
export default {
  name: 'Testvue',
  setup() {
    function myref(value,time = 1000) {
      let timer;
      return customRef((track, tigger) => {
        return {
          get() {
            track() // 通知vue追踪value的变化
            return value
          },
          set(newValue) {
            clearTimeout(timer)
            timer = setTimeout(() =>{
              value = newValue
              tigger() // 改完数据后 通知vue重新解析模板
            }, time)
          }
        }
      })
    }
    let keyword = myref('hello', 500)
    return {
      keyword
    }
  }
};

十一、provide和inject(祖孙组件之间通信)

父组件用provide提供数据 后代组件用inject使用数据
例 父组件:

import { reactive, provide} from "vue";

  setup() {
    let person = reactive({
      firstName: '张',
      lastName: '三'
    })
    provide('passData', person)
  }

后代组件:

import {inject} from "vue";
  setup() {
   let obj = inject('passData')
    return {
      obj
    }
  }

十二、Computed 计算属性

有简写和完整写法之分,完整写法考虑读写

   // 计算属性 简写 -- 单纯的读取
    person.fullName = computed(() => {
      return person.firstName + person.lastName
    })

    // 计算属性完整写法 --- 考虑修改
    person.fullName = computed({
      get() {
        return person.firstName + person.lastName
      },
      set(value) {
        const nameArr = value.split('-')
        person.firstName = nameArr[0]
        person.lastName = nameArr[1]
      }
    })

十三、watchEffect

不用指明监听那个属性的变化,回调函数中用到哪个属性,就监听那个属性变化

    watchEffect(() => {
      console.log(person.firstName);
    })

十四、watch监听

1、监听ref所定义的一个响应式数据

参数:

  1. 监听谁
  2. 回调函数
  3. 配置对象
<template>
  <h3>当前数值:{{ sum }}</h3>
  <button @click="sum++">增加</button>
</template>
<script>
import { ref, watch } from "@vue/runtime-core";
export default {
  setup() {
    let sum = ref(0);
    watch(
      sum,
      (newValue, oldValue) => {
        console.log(newValue, oldValue);
      },
      {
        immediate: true, // 立即监听
        deep: true, // 深度监听
      }
    );
    return {
      sum,
    };
  },
};
</script>

2、监听ref所定义的多个响应式数据

当监听多个响应式数据时,将多个数据放在一个数组里面,这样监听的newValue和oldValue都也都是也数组的形式呈现

<template>
  <h3>当前数值:{{ sum }}</h3>
  <button @click="sum++">增加</button>
  <h3>标题:{{ title }}</h3>
  <button @click="title+='~'">增加</button>
</template>
<script>
import { ref, watch } from "@vue/runtime-core";
export default {
  setup() {
    let sum = ref(0);
let title = ref("hi~");
// 监听多个
watch(
      [sum,title],
      (newValue, oldValue) => {
        console.log(newValue, oldValue);
      },
      {
        immediate: true, // 立即监听
        deep: true, // 深度监听
      }
    )
    return {
      sum,
      title,
    };
  },
};
</script>

3、监听reactive所定义的响应式数据的全部属性,

无法正确获取oldValue,并且强制开启了深度监听。

4、监听reactive所定义的响应式数据的某个属性

第一个参数要以回调函数返回写法

<template>
  <h3>姓名:{{Hero.username}}</h3>
  <h3>年龄:{{Hero.age}}</h3>
  <button @click="Hero.age++">改变年龄</button>
  <button @click="Hero.username += '~'">改变姓名</button>
</template>
<script>
import { reactive, watch } from "@vue/runtime-core";
export default {
  setup() {
    let Hero = reactive({
      username: '李四',
      age: 18,
      job: {
        j1: {
          speak: '你好'
        }
      }
    })
    // reactive所定义的响应式数据的某个属性
    watch(
      ()=>Hero.age, // 以回调形式拿到监听的属性
      (newValue, oldValue) => {
        console.log(newValue, oldValue);
      },
      {
        immediate: true, // 立即监听
        deep: true, // 深度监听
      })
    return {
     Hero
    };
  },
};
</script>

5、监听reactive所定义的响应式数据的多个属性

如果监听的属性嵌套层次比较深 则需要开启深度监听

watch(
      [()=>Hero.username, ()=>Hero.age, () =>Hero.job], // 以回调形式拿到监听的属性
      (newValue, oldValue) => {
        console.log(newValue, oldValue);
      },
      {
        immediate: true, // 立即监听
        deep: true, // 深度监听
    })

Logo

前往低代码交流专区

更多推荐