目录
vue3
一、环境
* 需要nodejs环境
* 安装:npm i -g @vue/cli
* 查看版本(需要在4.5.0以上):vue -V
* 脚手架初始化项目:vue create my-project
Please pick a preset:Manually select features
二、setup
1、ref
<template>
<div>
<div>{{count}}</div>
<button @click="update">按钮</button>
</div>
</template>
<script lang="ts">
import {defineComponent, ref} from 'vue';
export default defineComponent({
name: 'App',
// 初始化时执行,返回对象的属性和方法,模板中可以直接使用
setup() {
// ref(通常用于基本数据类型):定义一个响应式数据对象
// js中需使用响应式数据对象的value属性操作数据
// 如果ref()传入的是一个对象,则返回值.value是一个Proxy对象
// 模板中直接使用响应式数据对象渲染数据
const count = ref(0)
const update = function () {
count.value++
}
return {
count,
update
}
}
});
</script>
<style>
</style>
2、reactive
<template>
<div>
<div>{{person}}</div>
<button @click="update">按钮</button>
</div>
</template>
<script lang="ts">
import {defineComponent, reactive} from 'vue';
export default defineComponent({
name: 'App',
setup() {
// reactive:返回一个(深层的)响应式数据代理对象(ES6的Proxy对象)
const person = reactive({
name: 'linlong',
age: 28,
wife: {
name: 'tongliya',
age: 18
}
})
const update = function () {
person.name = 'wuxi'
person.age = 5
person.wife = {
name: 'jiangsu',
age: 28
}
}
return {
person,
update
}
}
});
</script>
<style>
</style>
3、一些细节知识点
* setup在beforeCreate之前执行
* setup中不能使用this来访问data/computed/methods/props
* setup不能是一个async函数(async函数返回的是一个promise)
* setup(props,{attrs,slots,emit})
props:父组件传入的,并且props中声明的,包含的所有属性的对象
attrs:父组件传入的,并且未在props中声明的,包含的所有属性的对象
slots:插槽
emit:分发事件
三、响应式数据原理
1、vue2
// vue2需要给每个属性都添加getter和setter(Object.defineProperty())
// vue3只需给属性是对象的添加代理操作(Proxy和Reflect)
// 数组元素无法直接修改,须通过$set()
Object.defineProperty(data, 'count', {
get() {},
set() {}
})
2、vue3
// 通过Proxy(代理): 拦截对对象属性的(13种)操作,包括属性的读写,添加, 删除(深度的)等...
// 通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作
// 数组的元素可以直接修改(arr[0]=28)
new Proxy(data, {
// 拦截读取属性值
get(target, prop) {
return Reflect.get(target, prop)
},
// 拦截设置属性值或添加新属性
set(target, prop, value) {
return Reflect.set(target, prop, value)
},
// 拦截删除属性
deleteProperty(target, prop) {
return Reflect.deleteProperty(target, prop)
}
})
四、计算属性
<template>
<div>
{{person}}<br/>
{{personCRI}}<br/>
</div>
</template>
<script lang="ts">
import {defineComponent, reactive, computed} from 'vue';
export default defineComponent({
name: 'App',
setup() {
const person = reactive({
name: 'linlong',
age: 28
})
// get函数中无法直接修改响应式数据的值
/*const personCRI = computed(() => {
const p = {...person}
p.age++
return p
})*/
const personCRI = computed({
get() {
const p = {...person}
p.age++
return p
}, set(val: any) {
person.name = val.name
person.age = val.age
}
})
// 必须personCRI.value={}方式修改值才会走set(不是深度的)
personCRI.value = {
name: 'wuxi',
age: 5
}
return {
person,
personCRI
}
}
});
</script>
<style>
</style>
五、监听属性
<template>
<div>
{{person}}<br/>
{{count}}<br/>
<button @click="update">按钮</button>
<br/>
</div>
</template>
<script lang="ts">
import {defineComponent, ref, reactive, watch, watchEffect} from 'vue';
export default defineComponent({
name: 'App',
setup() {
const person = reactive({
name: 'linlong',
age: 28,
wife: {
name: 'tongliya',
age: 18
}
})
const count = ref(0)
// ********
/*function update() {
person.wife.age++
}
watch(person, () => {
console.log(person)
}, {
immediate: true, // 是否初始化立即执行一次, 默认是false
deep: true, // 是否是深度监视, 默认是false
})*/
// ********
/*function update() {
person.wife.age = 28
}
// 除等号之前,所有使用到的响应式数据都会监听
// 默认 immediate: true,deep: false
watchEffect(() => {
person.wife.age = 1
})*/
// ********
function update() {
// count.value = 1
person.wife.age = 16
}
// 监听ref对象可直接指定。监听reactive对象,需要通过函数指定
watch([() => person.wife.age, count], () => {
console.log(person)
})
return {
person,
count,
update
}
}
});
</script>
<style>
</style>
六、生命周期
<template>
<div class="about">
<h2>msg: {{msg}}</h2>
<hr>
<button @click="update">更新</button>
</div>
</template>
<script lang="ts">
import {
ref,
onMounted,
onUpdated,
onUnmounted,
onBeforeMount,
onBeforeUpdate,
onBeforeUnmount
} from "vue"
export default {
beforeCreate () {
console.log('beforeCreate()')
},
created () {
console.log('created')
},
beforeMount () {
console.log('beforeMount')
},
mounted () {
console.log('mounted')
},
beforeUpdate () {
console.log('beforeUpdate')
},
updated () {
console.log('updated')
},
beforeUnmount () {
console.log('beforeUnmount')
},
unmounted () {
console.log('unmounted')
},
setup() {
const msg = ref('abc')
const update = () => {
msg.value += '--'
}
onBeforeMount(() => {
console.log('--onBeforeMount')
})
onMounted(() => {
console.log('--onMounted')
})
onBeforeUpdate(() => {
console.log('--onBeforeUpdate')
})
onUpdated(() => {
console.log('--onUpdated')
})
onBeforeUnmount(() => {
console.log('--onBeforeUnmount')
})
onUnmounted(() => {
console.log('--onUnmounted')
})
return {
msg,
update
}
}
}
</script>
七、hooks函数
import {reactive, onMounted} from "vue"
export default function (name: string, age: number) {
const person = reactive({
name,
age
})
onMounted(() => {
console.log(person)
})
return {person}
}
八、toRefs
<script lang="ts">
import {defineComponent, toRefs} from 'vue';
export default defineComponent({
name: 'App',
setup() {
const obj = {
name: 'huangtingting',
age: 18
}
// 会将对象的每一个属性都变为响应式数据(ref对象)
const person = toRefs(obj)
return {
...person
}
}
});
</script>
九、ref的另一个作用
<template>
<div ref="div"></div>
</template>
<script lang="ts">
import {defineComponent, ref, onMounted} from 'vue';
export default defineComponent({
name: 'App',
setup() {
// 通过ref函数获取页面元素
const div = ref<HTMLElement | null>(null)
onMounted(() => {
console.log(div.value)
})
return {
div
}
}
});
</script>
<style>
</style>
十、shallowReactive 与 shallowRef
浅度的reactive:对象的属性修改可以监听到,嵌套对象的属性修改不会监听到
浅度的ref:对象修改可以监听到,对象的属性修改不会监听到
十一、readonly 与 shallowReadonly
深只读:嵌套对象的属性也是只读
浅只读:嵌套对象的属性不是只读
十二、toRaw 与 markRaw
toRaw:将响应式数据对象转化为普通对象
markRaw:转化的对象不能成为响应式数据
十三、toRef
toRef(响应式数据对象,'属性'):返回值是一个响应式数据,与响应式数据对象的属性双向绑定
十四、customRef
<template>
<div>
{{personRef}}<br/>
<button @click="update">按钮</button>
</div>
</template>
<script lang="ts">
import {defineComponent, customRef} from 'vue';
export default defineComponent({
name: 'App',
setup() {
let person = {
name: '',
age: 0
}
// 自定义响应式数据
const personRef = customRef(((track, trigger) => {
return {
get() {
// 开启数据追踪
track()
return person
},
set(val: any) {
person = val
// 更新视图
trigger()
}
}
}))
return {
personRef,
update() {
personRef.value = {
name: 'linlong',
age: 28
}
}
}
}
});
</script>
<style>
</style>
十五、provide 与 inject
provide('名称',响应式数据):祖组件提供数据
inject('名称'):孙组件使用数据
十六、响应式数据的判断
isRef: 检查一个值是否为一个 ref 对象
isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
十七、手写API
1、shallowReactive 与 reactive
const reactiveHandler = {
get (target, key) {
if (key==='_is_reactive') return true
return Reflect.get(target, key)
},
set (target, key, value) {
const result = Reflect.set(target, key, value)
console.log('数据已更新, 去更新界面')
return result
},
deleteProperty (target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('数据已删除, 去更新界面')
return result
},
}
/*
自定义shallowReactive
*/
function shallowReactive(obj) {
return new Proxy(obj, reactiveHandler)
}
/*
自定义reactive
*/
function reactive (target) {
if (target && typeof target==='object') {
if (target instanceof Array) { // 数组
target.forEach((item, index) => {
target[index] = reactive(item)
})
} else { // 对象
Object.keys(target).forEach(key => {
target[key] = reactive(target[key])
})
}
const proxy = new Proxy(target, reactiveHandler)
return proxy
}
return target
}
/* 测试自定义shallowReactive */
const proxy = shallowReactive({
a: {
b: 3
}
})
proxy.a = {b: 4} // 劫持到了
proxy.a.b = 5 // 没有劫持到
/* 测试自定义reactive */
const obj = {
a: 'abc',
b: [{x: 1}],
c: {x: [11]},
}
const proxy = reactive(obj)
console.log(proxy)
proxy.b[0].x += 1
proxy.c.x[0] += 1
2、shallowRef 与 ref
/*
自定义shallowRef
*/
function shallowRef(target) {
const result = {
_value: target, // 用来保存数据的内部属性
_is_ref: true, // 用来标识是ref对象
get value () {
return this._value
},
set value (val) {
this._value = val
console.log('set value 数据已更新, 去更新界面')
}
}
return result
}
/*
自定义ref
*/
function ref(target) {
if (target && typeof target==='object') {
target = reactive(target)
}
const result = {
_value: target, // 用来保存数据的内部属性
_is_ref: true, // 用来标识是ref对象
get value () {
return this._value
},
set value (val) {
this._value = val
console.log('set value 数据已更新, 去更新界面')
}
}
return result
}
/* 测试自定义shallowRef */
const ref3 = shallowRef({
a: 'abc',
})
ref3.value = 'xxx'
ref3.value.a = 'yyy'
/* 测试自定义ref */
const ref1 = ref(0)
const ref2 = ref({
a: 'abc',
b: [{x: 1}],
c: {x: [11]},
})
ref1.value++
ref2.value.b[0].x++
console.log(ref1, ref2)
3、shallowReadonly 与 readonly
const readonlyHandler = {
get (target, key) {
if (key==='_is_readonly') return true
return Reflect.get(target, key)
},
set () {
console.warn('只读的, 不能修改')
return true
},
deleteProperty () {
console.warn('只读的, 不能删除')
return true
},
}
/*
自定义shallowReadonly
*/
function shallowReadonly(obj) {
return new Proxy(obj, readonlyHandler)
}
/*
自定义readonly
*/
function readonly(target) {
if (target && typeof target==='object') {
if (target instanceof Array) { // 数组
target.forEach((item, index) => {
target[index] = readonly(item)
})
} else { // 对象
Object.keys(target).forEach(key => {
target[key] = readonly(target[key])
})
}
const proxy = new Proxy(target, readonlyHandler)
return proxy
}
return target
}
/* 测试自定义readonly */
/* 测试自定义shallowReadonly */
const objReadOnly = readonly({
a: {
b: 1
}
})
const objReadOnly2 = shallowReadonly({
a: {
b: 1
}
})
objReadOnly.a = 1
objReadOnly.a.b = 2
objReadOnly2.a = 1
objReadOnly2.a.b = 2
4、isRef, isReactive 与 isReadonly
/*
判断是否是ref对象
*/
function isRef(obj) {
return obj && obj._is_ref
}
/*
判断是否是reactive对象
*/
function isReactive(obj) {
return obj && obj._is_reactive
}
/*
判断是否是readonly对象
*/
function isReadonly(obj) {
return obj && obj._is_readonly
}
/*
是否是reactive或readonly产生的代理对象
*/
function isProxy (obj) {
return isReactive(obj) || isReadonly(obj)
}
/* 测试判断函数 */
console.log(isReactive(reactive({})))
console.log(isRef(ref({})))
console.log(isReadonly(readonly({})))
console.log(isProxy(reactive({})))
console.log(isProxy(readonly({})))
十八、Teleport
<teleport to="body">
<div>该标签会添加到body标签下</div>
</teleport>
十九、Suspense
<template>
<Suspense>
<template v-slot:default>
<llComponent></llComponent>
</template>
<template v-slot:fallback>
<div>加载中...</div>
</template>
</Suspense>
</template>
<script lang="ts">
import {defineComponent, defineAsyncComponent} from 'vue';
export default defineComponent({
name: 'App',
components: {
// 加载异步组件
llComponent: defineAsyncComponent(() => import('./views/llComponent.vue'))
},
setup() {
return {}
}
});
</script>
<style scoped>
</style>
<template>
<div>{{msg}}</div>
</template>
<script lang="ts">
export default {
name: 'llComponent',
setup() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
msg: '你好,世界!'
})
}, 3000)
})
}
}
</script>
<style scoped>
</style>