目录
一、初识vue3.0
1.1 vue3.0 的优点
1.2 vite 的基本使用
1.3 如何创建一个Vue3.0的项目
二、组合API
2.1 什么是选项API 和组合PAI
2.2 setup 函数
2.3 生命周期函数
2.4 reactive 函数
2.5 toRef 函数
2.6 toRefs 函数
2.7 ref 函数
2.8 demo
2.9 computed 函数
2.10 watch 函数
2.11 ref 属性
2.12 父子通讯
2.13 依赖注入
2.14 v-model 语法糖
三、EventBus
四、代码组织能力
五、Teleport
六、VueX中如何使用
6.1 同步方法改变数据
6.2 异步方法改变数据
现在主流组件库都已经发布了支持vue3.0的版本,其他生态也在不断地完善中,这是趋势。
,用不到就不会打包)。vite是什么:
官方文档(opens new window)https://cn.vitejs.dev/
vite基本使用:
npm init vite-app 项目名称
或者 yarn create vite-app 项目名称
npm i
或者 yarn
npm run dev
或者 yarn dev
总结: vite是什么?
基本步骤:
1.安装最新版本的Vue-cli工具,最新版本工具已经提供Vue3-preview
npm install -g @vue/cli
# OR
yarn global add @vue/cli
2.创建项目选择
3.根实例初始化:
在2.x中,通过new Vue()
的方法来初始化
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
在3.x中Vue不再是一个构造函数,通过createApp方法初始化
createApp(App).use(store).use(router).mount('#app')
选项API:
在 Vue2.x 中使用的都是选项API,比如要定义数据就应该在 data 选项下、要定义方法就应该在 methods 选项下、要定义计算属性就应该在 computed 选项下...,这其实就是选项API,也叫 Options API
优点:易于学习和使用,写代码的位置已经约定好
缺点:代码组织性差,相似的逻辑代码不便于复用,逻辑复杂代码多了不好阅读
补充:虽然提供mixins用来封装逻辑,但是出现数据函数覆盖的概率很大,不好维护
组合API:
在 Vue3.x 中使用的就是组合API
代码风格:一个功能逻辑的代码组织在一起(包含数据,函数...)
优点:功能逻辑复杂繁多情况下,各个功能逻辑代码组织再一起,便于阅读和维护
缺点:需要有良好的代码组织能力和拆分逻辑能力
补充:vue3.0也支持vue2.x选项API写法
使用细节:
setup
是一个新的组件选项,作为组件中使用组合API的起点
从组件生命周期来看,它的执行在组件实例创建之前(vue2.x的beforeCreate
)执行
这就意味着在setup
函数中 this
还不是组件实例,this
此时是 undefined,因此在setup中不能使用this
在模版中需要使用的数据和函数,需要在 setup
返回
App.vue,
{{msg}}
回顾vue2.x生命周期钩子函数:
认识vue3.0生命周期钩子函数:
setup
创建实例前onBeforeMount
挂载DOM前onMounted
挂载DOM后onBeforeUpdate
更新组件前onUpdated
更新组件后onBeforeUnmount
卸载销毁前onUnmounted
卸载销毁后App.vue,
根组件
总结: 组合API的生命周期钩子有7个,可以多次使用同一个钩子,执行顺序和书写顺序相同
定义响应式数据
reactive是一个函数,它可以定义一个复杂数据类型(对象、数组),成为响应式数据
总结: 通常是用来定义响应式对象数据
App.vue,
{{obj.name}}
{{obj.age}}
定义响应式数据
toRef是函数,转换响应式对象中某个属性为单独响应式数据,并且值是关联的
使用场景:有一个响应式对象数据,但是模版中只需要使用其中一项数据
App.vue,
{{obj.name}}
{{obj.age}}
定义响应式数据
toRefs是函数,转换响应式对象中所有属性为单独响应式数据,对象成为普通对象,并且值是关联的
使用场景:剥离响应式对象(解构|展开),想使用响应式对象中的多个或者所有属性做为响应式数据
App.vue,
{{name}}
{{age}}
定义响应式数据
ref函数,常用于将简单数据类型定义为响应式数据,但是也可以定义复杂数据类型的响应式数据
当得到的数据类型未知时,可以用 ref
const data = ref(null)
setTimeout(() => {
data.value = res.data
}, 1000)
使用场景:
App.vue,
{{name}}
{{age}}
App.vue,
x:{{x}}
y:{{y}}
{{count}}
定义计算属性:当需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据
computed函数,是用来定义计算属性的,计算属性不能修改
目的:让计算属性支持双向数据绑定
总结:计算属性两种用法:
i. 基本用法:
App.vue,
今年:{{age}}岁
后年:{{newAge}}岁
ii. 高级用法:
App.vue,
今年:{{age}}岁
后年:{{newAge}}岁
使用 v-model 绑定计算属性
定义计算属性
watch函数,是用来定义侦听器的:
App.vue
count的值:{{count}}
App.vue
count的值:{{count}}
{{obj.name}}
{{obj.age}}
App.vue
{{obj.name}}
{{obj.age}}
需要写成函数返回该属性的方式才能监听到
App.vue
count的值:{{count}}
{{obj.name}}
{{obj.age}}
App.vue
count的值:{{count}}
{{obj.name}}
{{obj.age}}
{{obj.brand.name}}
获取DOM或者组件实例可以使用ref属性,写法和vue2.0需要区分开
i. 获取单个DOM或者组件:
App.vue,
我是box
ii. 获取v-for遍历的DOM或者组件:
App.vue,
- 第{{i}}个li
总结:
单个元素:先申明ref响应式数据,返回给模版使用,通过ref绑定数据
遍历的元素:先定义一个空数组,定一个函数获取元素,返回给模版使用,通过ref绑定这个函数
// ref获取v-for遍历的DOM元素,需要在组件更新的时候重置接受dom元素的数组。
onBeforeUpdate(()=>{
list = []
})
i. 父传子:
App.vue
父组件
{{money}}
Son.vue
子组件
{{money}}
注意点:
不能使用 ES6 解构,它会消除 prop 的响应性;如果需要解构 prop,可以在 setup
函数中使用toRefs函数来完成此操作:例如,
// MyBook.vue
import { toRefs } from 'vue'
setup(props) {
const { title } = toRefs(props)
console.log(title.value)
}
如果 title
是可选的 prop,则传入的 props
中可能没有 title
。在这种情况下,toRefs
将不会为 title
创建一个 ref 。你需要使用 toRef
替代它:例如,
// MyBook.vue
import { toRef } from 'vue'
setup(props) {
const title = toRef(props, 'title')
console.log(title.value)
}
ii. 子传父:
App.vue
父组件
{{money}}
Son.vue
子组件
{{money}}
注意:
context
是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context
使用 ES6 解构。例如:
// MyBook.vue
export default {
setup(props, { attrs, slots, emit, expose }) {
...
}
}
iii. 扩展:
.sync
除去v-model实现双向数据绑定的另一种方式
v-model:money="money"
即可
总结:
setup(props){ // props就是父组件数据 }
setup(props,{emit}){ // emit 就是触发事件函数 }
v-model
和 .sync
已经合并成 v-model
指令使用provide函数和inject函数完成后代组件数据通讯
使用场景:有一个父组件,里头有子组件,有孙组件,有很多后代组件,共享父组件数据
Provide / Inject的应用,它们在3.x中得到了增强:
App.vue,
我是父组件
{{money}}
Son1.vue,
我是儿子组件
{{money}}
GrandSon.vue,
我是孙子组件
{{money}}
总结:
在vue2.0中v-mode语法糖简写的代码:
在vue3.0中v-model语法糖有所调整:
App.vue
父组件
{{count}}
Son2.vue
子组件
{{modeValue}}
总结: vue3.0封装组件支持v-model的时候,父传子:modelValue
子传父 @update:modelValue
补充: vue2.0的 xxx.sync
语法糖解析 父传子 :xxx
子传父 @update:xxx
在vue3.0 使用 v-model:xxx
代替
在 vue3.x 中无法使用EventBus
在 src 目录下新建一个名为 utils 的文件夹,并在该文件夹里新建一个名为 mitt.js 的文件
并通过 npm install --save mitt 安装 mitt
在 main.js 里引入(import "./utils/mitt")
在 src/components 目录下新建一个名为 Child 的文件夹,并在该文件夹里新建一个名为 index.vue 的文件
mitt.js,
import mitt from "mitt"
const emitter = mitt();
export default emitter;
src/components/Child/index.vue,
Child页面
{{message}}
在2.x中通过EventBus的方法来实现组件通信:(Vue2Demo.vue)
var EventBus = new Vue()
Vue.prototype.$EventBus = EventBus
...
this.$EventBus.$on() this.$EventBus.$emit()
在3.x中移除了$on, $off等方法(参考rfc),而是推荐使用mitt方案来代替(Vue3Demo.vue)
vue3版本
关于代码组织能力,其实很简单,就是将多个组件都需要用到的一些方法等提取出来,单独放在一个文件里,然后分别引用即可
关于这一部分其实没什么好说的,都比较简单
举个例子来说就是,你在书写代码时可以指定将其加到某一个class/id...属性为xxx的结构里:
这是一个独立的结构
类似于上面的代码,就是将里面书写的 h3 放到一个属性为id=app的结构里
Home.vue
{{name}}
About.vue
This is an about page
{{name}}
store/index.js
import { createStore } from 'vuex'
//VueX 数据管理框架
//VueX 创建了一个全局唯一的仓库,用来存放全局的数据
export default createStore({
// 存放全局的数据
state: {
name: 'dell'
},
//mutation 里面只允许写同步代码,不允许写异步代码
//commit和mutation作关联
mutations: {
//第四步,对应的 mutation 被执行
changeName(state, str) {
//第五步 在 mutation 里修改数据
// this.state.name = 'lee';
state.name = str;
}
},
modules: {}
})
About.vue
This is an about page
{{name}}
Home.vue
{{name}}
index.js
import { createStore } from 'vuex'
//VueX 数据管理框架
//VueX 创建了一个全局唯一的仓库,用来存放全局的数据
export default createStore({
// 存放全局的数据
state: {
name: 'dell'
},
//mutation 里面只允许写同步代码,不允许写异步代码
//commit和mutation作关联
mutations: {
//第四步,对应的 mutation 被执行
changeName(state, str) {
//第五步 在 mutation 里修改数据
// this.state.name = 'lee';
state.name = str;
}
},
// dispatch 和 actions 作关联
actions: {
//第二步,store 感知到了你触发了一个叫做 change 的 action
//执行 change()方法
getData(store) {
setTimeout(() => {
//第三步,提交一个 commit,触发一个 mutation
store.commit('changeName', 'hello');
}, 2000)
}
},
modules: {}
})