第三章、Vue3高级
目录
- 十、Vue3的组件化(二)
- 1、组件的拆分和嵌套
- 2、组件的css作用域(vue-loader)
- 3、组件的通信props和$emit
- 4、插槽slot
- 十一、Vue3的组件化(三)
- 1、动态组件component的使用
- 2、keep-alive
- 3、异步组件和代码分包
- 4、$refs的使用
- 5、$parent、$root、$el
- 6、生命周期
- 7、组件的v-model
- 十二、Vue3过渡&动画实现
- 1、过渡动画
- 2、帧动画
- 3、动画模式mode
- 4、animate.css
- 5、gsap
- 6、列表的过渡
- 7、列表的交错过渡
- 十三、composition api(一)
- 1、mixin基本使用
- 2、mixin的合并规则
- 3、mixin全局混入
- 4、extends
- 5、setup参数和返回值
- 6、setup函数源码阅读
- 7、reactive api
- 8、ref api
- 9、ref浅层解包
- 10、readonly
- 十四、composition api(二)
- 1、reactive判断的api
- 2、toRefs和toRef
- 3、ref其他的api
- 4、customRef
- 5、computed
- 6、watchEffect
- 7、setup引用元素和watchEffect执行时机
- 8、watch
- 十五、composition api(三)
- 1、生命周期钩子
- 2、provide和inject
- 3、useCounter案例
- 4、useTitle案例
- 5、useScrollPosition案例
- 6、useMousePosition案例
- 7、useLocalStorage案例
- 8、setup顶层编写方式
- 9、render和h函数
- 10、render函数实现计数器
- 11、render组件和插槽的使用
- 12、render函数jsx写法
十、Vue3的组件化(二)
1、组件的拆分和嵌套
* 对组件进行拆分,拆分成一个个小的组件
* 再将这些组件组合嵌套在一起,最终形成我们的应用程序
2、组件的css作用域(vue-loader)
3、组件的通信props和$emit
- 概念
* 父子组件通信:
- 父传子:通过props属性
- 子传父:通过$emit触发事件
* 非父子组件通信方式
- provide和inject
- mitt全局事件总线
- props用法
- props命名
HTML中标签的属性名大小写不敏感,浏览器会把大写字符解释为小写字符。
所以模板中的属性名(prop)需要使用短横线分隔命名(组件名也是这样)
- 非prop的attribute
* 非prop的attribute:当我们传递给一个组件某个属性,但是该属性并没有定义对应的props或者emits时,
就称之为非prop的attribute
* attribute继承:当组件有单个根节点时,非prop的attribute将自动添加到根节点的attribute中
黄婷婷
黄婷婷
- 自定义事件
{{name}}:{{age}}
- provide和inject基本使用
{{name}}
{{age.value}}
- 全局事件总线mitt库
# Vue3从实例中移除了$on、$off、$once方法,希望继续使用全局事件总线,要安装第三方的mitt库
npm i -S mitt
// 工具
import mitt from "mitt";
const emitter = mitt()
export default emitter
{{person.name}}:{{person.age}}
- mitt的事件取消
// 取消emitter中所有的监听
emitter.all.clear()
// 定义一个函数
function onFoo() {}
emitter.on("foo", onFoo)// 监听
emitter.off("foo", onFoo)// 取消监听
4、插槽slot
- 基本使用
张婧仪
黄婷婷
孟美岐
张婧仪
- 渲染作用域
- 父级模板里的所有内容都是在父级作用域中编译的
- 子模板里的所有内容都是在子作用域中编译的
- 作用域插槽
{{row.name}}
{{row.age}}
- 独占默认插槽的细节
{{row.name}}
{{row.age}}
十一、Vue3的组件化(三)
1、动态组件component的使用
2、keep-alive
first
{{count}}
3、异步组件和代码分包
- webpack的代码分包
// 通过import函数导入的模块,后续webpack对其进行打包的时候就会进行分包的操作
import('./utils/index').then(res => {
console.log(res.sum(1, 2))
})
- 异步组件
- 异步组件和Suspense
<异步组件>异步组件>
4、$refs的使用
黄婷婷
5、$parent、$root、$el
* 通过组件实例的$parent来访问父组件
* 通过组件实例的$root来访问根组件
* 通过组件实例的$el来访问组件的根元素(测试发现如果是多个根元素$el为#text节点)
* 注意:在Vue3中已经移除了$children的属性
6、生命周期
- 生命周期
{{name}}
- 缓存组件的生命周期
7、组件的v-model
{{name}}
{{age}}
十二、Vue3过渡&动画实现
1、过渡动画
- 基本使用
黄婷婷
- 概念
* 当插入或删除包含在transition组件中的元素时,vue将会做以下处理
- 自动嗅探目标元素是否应用了css过渡或者动画,如果有,那么在恰当的时机添加/删除css类名
- 如果transition组件提供了javascript钩子函数,这些钩子函数将在恰当的时机被调用
- 如果没有找到javascript钩子并且也没有检测到css过渡/动画,
DOM插入、删除操作将会立即执行
* 我们会发现上面提到了很多个class,事实上vue就是帮助我们在这些class之间来回切换完成的动画
- v-enter-from:定义进入过渡的开始状态。在元素被插入之前生效,
在元素被插入之后的下一帧移除
- v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,
在元素被插入之前生效,在过渡/动画完成之后移除。
这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数
- v-enter-to:定义进入过渡的结束状态。在元素被插入之后下一帧生效
(与此同时v-ente-from被移除),在过渡/动画完成之后移除
- v-leave-from:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除
- v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,
在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。
这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数
- v-leave-to:离开过渡的结束状态。在离开过渡被触发之后下一帧生效
(与此同时v-leave-from被删除),在过渡/动画完成之后移除
* class的name命名规则如下:
- 如果我们使用的是一个没有name的transition,name所有的class是以v-作为默认前缀
- 如果我们添加了一个name属性,比如,
那么所有的class会以fade-开头
2、帧动画
- 基本使用
黄婷婷
- 过渡动画和帧动画同时使用
- 明确指定动画的时间
3、动画模式mode
- mode
- appear
4、animate.css
- 配合属性name使用
# 安装
npm i -S animate.css
// 入口文件引入
import "animate.css"
黄婷婷
- 配合属性enter-active-class或leave-active-class使用
黄婷婷
5、gsap
- transition动画钩子函数
- gsap基本使用
# 安装
npm i -S gsap
黄婷婷
- gsap实现数字翻牌器
{{showNumber}}
6、列表的过渡
# 安装
npm i -S lodash
{{item}}
7、列表的交错过渡
{{item}}
十三、composition api(一)
1、mixin基本使用
{{message}}
2、mixin的合并规则
* 如果是data函数的返回值对象
- 返回值对象默认情况下会进行合并
- 如果data返回值对象的属性发生了冲突,那么会保留组件自身的数据
* 如果生命周期钩子函数
- 生命周期的钩子函数会被合并到数组中,都会被调用
* 值为对象的选项,例如methods、components、directives将被合并为同一个对象
- 比如都有methods选项,并且都定义了方法,那么它们都会生效
- 但是如果对象的key相同,那么会取组件对象的键值对
3、mixin全局混入
import {createApp} from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mixin({
data() {
return {
message: ""
}
},
mounted() {
this.message = "黄婷婷"
},
methods: {
clickHandler() {
this.message = "孟美岐"
}
}
})
app.mount('#app')
4、extends
{{message}}
5、setup参数和返回值
{{name}}
{{age}}
6、setup函数源码阅读
* setup()是在解析其它组件选项之前被调用的,所以setup()内部的this的行为与其它选项
中的this完全不同。(packages/runtime-core/src/renderer.ts:526)
7、reactive api
{{state.age}}
8、ref api
{{age}}
9、ref浅层解包
* template模板中直接使用ref对象,会自动解包
* 当ref对象外层包裹一层普通对象,则不会自动解包
* 当ref对象外层包裹的是reactive对象,也会自动解包
10、readonly
十四、composition api(二)
1、reactive判断的api
* isProxy
- 检查对象是否是由reactive或readonly创建的proxy
* isReactive
- 检查对象是否是由reactive创建的响应式代理
- 如果该代理是readonly建的,但包裹了由reactive创建的另一个代理,它也会返回true
* isReadonly
- 检查对象是否是由readonly创建的只读代理
* toRaw
- 返回reactive或readonly代理的原始对象(不建议保留对原始对象的持久引用。请谨慎使用)
* shallowReactive
- 创建一个响应式代理,它跟踪其自身property的响应性,但不执行嵌套对象的深层响应式转换
(深层还是原生对象)
* shallowReadonly
- 创建一个proxy,使其自身的property为只读,但不执行嵌套对象的深度只读转换
(深层还是可读、可写的)
2、toRefs和toRef
{{name}}:{{age}}
3、ref其他的api
{{info}}
4、customRef
{{info}}
5、computed
{{fullName}}
6、watchEffect
{{age}}
7、setup引用元素和watchEffect执行时机
黄婷婷
8、watch
{{name}}:{{friend.age}}
十五、composition api(三)
1、生命周期钩子
{{name}}
2、provide和inject
{{age}}
3、useCounter案例
{{counter}}
{{doubleCounter}}
// useCounter.js
import {ref, computed} from "vue"
export default function () {
const counter = ref(0)
const doubleCounter = computed(() => counter.value * 2)
const increment = () => counter.value++
const decrement = () => counter.value--
return {
counter,
doubleCounter,
increment,
decrement,
}
}
4、useTitle案例
// useTitle.js
import {ref, watch} from "vue"
export default function (title = "姜贞羽") {
const titleRef = ref(title)
watch(titleRef, (newValue) => {
document.title = newValue
}, {
immediate: true
})
return titleRef
}
5、useScrollPosition案例
scrollX:{{scrollX}}
scrollY:{{scrollY}}
// useScrollPosition.js
import {ref} from "vue"
export default function () {
const scrollX = ref(0)
const scrollY = ref(0)
document.addEventListener("scroll", () => {
scrollX.value = window.scrollX
scrollY.value = window.scrollY
})
return {
scrollX,
scrollY
}
}
6、useMousePosition案例
mouseX:{{mouseX}}
mouseY:{{mouseY}}
// useMousePosition.js
import {ref} from "vue"
export default function () {
const mouseX = ref(0)
const mouseY = ref(0)
window.addEventListener("mousemove", (event) => {
mouseX.value = event.pageX
mouseY.value = event.pageY
})
return {
mouseX,
mouseY
}
}
7、useLocalStorage案例
{{person}}
import {ref, watch} from "vue"
export default function (key, value) {
const data = ref(value)
if (value) {
window.localStorage.setItem(key, JSON.stringify(value))
} else {
data.value = JSON.parse(window.localStorage.getItem(key))
}
watch(data, (newValue) => {
window.localStorage.setItem(key, JSON.stringify(newValue))
})
return data
}
8、setup顶层编写方式
{{person}}
9、render和h函数
黄婷婷
10、render函数实现计数器
11、render组件和插槽的使用
12、render函数jsx写法
- 安装
# 测试结果不用安装,所以也不用配置
npm i @vue/babel-plugin-jsx -D
- 配置(babel.config.js)
module.exports = {
plugins: [
"@vue/babel-plugin-jsx"
]
}
- jsx计数器案例
- jsx组件和插槽的使用