目录
一、使用vite创建项目
npm init vite -y
// package.json
"scripts": {
"dev": "vite", // 项目启动
"build": "vue-tsc && vite build", // 项目打包
"preview": "vite preview" // 项目预览(打包后的,需要先执行 npm run build 才行)
},
// 项目依赖
"dependencies": {
"vue": "^3.2.47"
},
// 开发依赖
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"typescript": "^5.0.2",
"vite": "^4.3.9",
"vue-tsc": "^1.4.2"
}
在npm run dev的时候,不会显示局域网地址
VITE v4.3.9 ready in 1006 ms
➜ Local: http://127.0.0.1:5173/
➜ Network: use --host to expose
➜ press h to show help
需要在scripts的dev中加入--host
"scripts": {
"dev": "vite --host", // 这里添加
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
二、常用的Composition Api(组合式api)
1. setup
1. 组件中所用到的数据、方法等,均要配置在setup中。
2. setup函数的两种返回值:
1. 若返回一个对象,则对象中的属性、方法,在模版中均可以直接使用。
2. 若返回一个渲染函数;则可以自定义渲染内容。(了解)
3. setup执行时机在beforeCreate之前执行,this为undefined
4. setup可以接受两个参数,参数1:props(响应式数据) 参数2:context(上下文对象)
setup(props, context)
// 具体看第4、5点
props:需要通过props接受(和vue2相同)才能获取props
context: attrs: Proxy(Object) // props未接收的数据,会出现在attrs中
emit: (event, ...args) => instance.emit(event, ...args)
expose: (exposed) => {…}
slots: Proxy(Object)
<script>
export default {
setup(props, context) {
// 透传 Attributes(非响应式的对象,等价于 $attrs)
console.log(context.attrs)
// 插槽(非响应式的对象,等价于 $slots)
console.log(context.slots)
// 触发事件(函数,等价于 $emit)
console.log(context.emit)
// 暴露公共属性(函数)
console.log(context.expose)
}
}
</script>
2. ref函数
2.1 ref将普通数据变成响应式数据
通过 .value 来获取值
基本数据类型
<template>
<div>
<p>{{ name }}{{ age }}</p>
<button @click="changeInfo">按钮</button>
</div>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
// 数据
let name = ref('xiaotian');
let age = ref(19);
// 方法
function changeInfo() {
name.value = 'wifi';
age.value = 20
}
return {
name, age, changeInfo
}
}
}
</script>
引用数据类型
<template>
<div>
<p>name:{{ obj.name }}</p>
<p>age:{{ obj.age }}</p>
<button @click="changeInfo">按钮</button>
</div>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
const obj = ref({
name: 'xiaotian',
age: 19
})
const changeInfo = () => {
obj.value.name = 'wifi'
obj.value.age = 20
}
return {
obj, changeInfo
}
}
}
</script>
2.2 用来获取dom(vue2的$ref)
<template>
<div>
<p ref="pDom">这是一个p标签</p>
</div>
</template>
<script>
import { ref, onMounted } from "vue";
export default {
setup() {
const pDom = ref()
onMounted(() => {
// pDom是一个ref对象
console.log(pDom.value);
})
return {
pDom // 返回的pDom要和模版中ref绑定的名字要相同
}
}
}
</script>
3. reactive函数
用来定义引用数据类型的响应式,获取数据不用 .value
<template>
<div>
<p>name:{{ obj.name }}</p>
<p>age:{{ obj.age }}</p>
<button @click="changeInfo">按钮</button>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
setup() {
const obj = reactive({
name: 'xiaotian',
age: 19
})
const changeInfo = () => {
obj.name = 'wifi'
obj.age = 20
}
return {
obj, changeInfo
}
}
}
</script>
4. props
<!-- 父组件 -->
<template>
<Son msg="hello"/>
</template>
<!-- 子组件 -->
<template>
<div></div>
</template>
<script>
export default {
props: ['msg'],
setup(props, context) {
console.log(props) // Proxy(Object) {msg: 'hello'}
}
}
</script>
5. emit(书写自定义事件)
<!-- 子组件 -->
<template>
<div>
<button @click="handleClick">点击触发自定义事件</button>
</div>
</template>
<script>
export default {
// 要将自定义事件名声明一下
emits: ['hello'],
setup(props, context) {
const handleClick = () => {
context.emit('hello', '我是子组件')
}
return { handleClick }
}
}
</script>
<!-- 父组件 -->
<template>
<div>
<Son @hello="handleHello" msg="Vite + Vue" />
</template>
<script>
import Son from './components/Son.vue'
export default {
components: {
Son
},
setup() {
const handleHello = (data) => {
console.log(data);
}
return { handleHello }
}
}
</script>
6. computed计算属性
<script>
import { reactive, computed } from 'vue';
export default {
setup() {
let person = reactive({
firstName: 'xiao',
lastName: 'tian'
})
// 计算属性 简写形式(没有考虑计算属性被修改的情况)
person.fullName = computed(() => {
return person.firstName + '-' + person.lastName
})
// 计算属性 完整写法
person.fullName = computed({
get() {
return person.firstName + '-' + person.lastName
},
set(val) {
const newArr = val.split('-')
person.firstName = newArr[0]
person.lastName = newArr[1]
}
})
return { person }
}
}
</script>
7. watch 监听器
7.1 使用vue2写法
<script>
import { ref } from 'vue';
export default {
setup() {
let num = ref(0)
return { num }
},
watch: {
// 简单写法
num(newVal, oldVal) {
console.log(newVal, oldVal);
}
// 完整写法
num: {
handler(newVal, oldVal) {
console.log(newVal, oldVal);
}
}
}
}
</script>
7.2 vue3写法(5种情况)
1. ref定义的响应式数据,如果是基本数据类型,则watch不需要.value, 如果是引用数据类型就可以开启deep深度监听
2. 当数据嵌套比较深的时候,需要开启deep
8. watchEffect
<script>
import { reactive, ref, watchEffect } from 'vue';
export default {
setup() {
let num = ref(0)
let person = reactive({
name: 'xiaotian',
age: 19,
a: {
b: {
c: 1
}
}
})
watchEffect(() => {
// 一加载完就会执行一次,监视回调中用到的响应式数据,深层数据也能监听到
console.log('watchEffect', num.value);
console.log('watchEffect', person.a.b.c);
})
// watchEffect返回的是一个停止侦听函数,可以调用它来停止副作用代码的执行。
const stop = watchEffect(() => {
// ...
})
stop()
return { num, person }
}
}
</script>
9. 生命周期
配置项写法
<script>
export default {
// 配置项写法
beforeCreate() {
},
created() {
},
beforeMount() {
},
mounted() {
},
beforeUpdate() {
},
updated() {
},
beforeUnmount() {
// vue3已经不是beforeDestroy,改为beforeUnmount
},
unmounted() {
// vue3已经不是destroyed,改为unmounted
}
}
</script>
组合式api(在setup中写)
beforeCreate => setup()
created => setup()
beforeMount => onBeforeMount()
mounted => onMounted()
beforeUpdate => onBeforeUpdate()
updated => onUpdated()
beforeUnmount => onBeforeUnmount()
unmounted => onUnmounted()
10. 自定义hook
将需要复用的逻辑抽离出来
// hooks/usePoint.js
import { reactive, onMounted, onBeforeUnmount } from 'vue';
export default () => {
let point = reactive({
x: 0,
y: 0
})
const savePoint = (e) => {
point.x = e.pageX
point.y = e.pageY
}
onMounted(() => {
window.addEventListener('click', savePoint)
})
onBeforeUnmount(() => {
window.removeEventListener('click', savePoint)
})
return point
}
<template>
<div>
<p>x: {{ point.x }}</p>
<p>y: {{ point.y }}</p>
</div>
</template>
<script>
import savePoint from '../hooks/usePoint'
export default {
setup() {
const point = savePoint()
return { point }
}
}
</script>
11. toRef 和 toRefs
<template>
<div>
num: {{ num }}
<button @click="num++">num++</button>
</div>
</template>
<script>
import { reactive } from 'vue';
export default {
setup() {
const obj = reactive({
num: 10
})
return {
num: obj.num // 这样会导致数据丢失响应式,所以需要对象数据的某个响应式,就需要用到toRef
}
}
}
</script>
toRef:创建一个 ref 对象,其value值指向另一个对象中的某个属性。语法:const name = toRef(person, 'name')
。就是将不是ref的数据变成ref数据
<template>
<div>
num: {{ num }}
<button @click="num++">num++</button>
</div>
</template>
<script>
import { reactive, toRef } from 'vue';
export default {
setup() {
const obj = reactive({
num: 10
})
let num = toRef(obj, 'num')
return {
num
}
}
}
</script>
toRefs
<template>
<div>
num: {{ num }}
<button @click="num++">num++</button>
</div>
</template>
<script>
import { reactive, toRefs } from 'vue';
export default {
setup() {
const obj = reactive({
num: 10,
str: 'hello'
})
return {
...toRefs(obj)
}
}
}
</script>
三、其他Composition Api
1. customRef
-
作用:创建一个自定义的ref,并对其依赖项跟踪和更新出啊发进行显示控制。
-
写法:
<template>
<input type="text" v-model="keyword">
<h3>{{ keyword }}</h3>
</template>
<script>
import { customRef } from 'vue';
export default {
setup() {
// let keyword = ref('hello'); // 使用vue提供的ref
// 自定义的ref:myRef
function myRef(val) {
return customRef((track, trigger) => {
// customRef的回调函数必须返回一个对象
return {
get() {
track(val) // 第三步:通知vue,追踪val数据的变化
return val
},
set(newVal) {
val = newVal // 第一步
trigger() // 第二步通知vue去重新解析模板
}
}
})
}
let keyword = myRef('hello'); // 使用自定义的ref
return { keyword }
}
}
</script>
-
实现防抖效果:
<script>
import { customRef } from 'vue';
export default {
setup() {
function myRef(val) {
let timer = null;
return customRef((track, trigger) => {
return {
get() {
track(val)
return val
},
set(newVal) {
clearInterval(timer);
timer = setTimeout(() => {
val = newVal
trigger()
}, 1000)
}
}
})
}
let keyword = myRef('hello');
return { keyword }
}
}
</script>
2. provide 与 inject
-
作用:实现祖孙组件间的通信,数据是响应式的
-
用法:父组件有一个
provide
来提供数据,子组件有一个inject
来使用数据
3. 响应式数据的判断
-
isRef:检查一个值是否为一个ref对象
-
isReactive:检查一个对象是否是由
reactive
创建的响应式代理
四、异步引入组件
-
defineAsyncComponent 和 Suspense组件
<template>
<Suspense>
<!-- 加载完成展示的内容 -->
<template v-slot:default>
<Child/>
</template>
<!-- 加载中展示的内容 -->
<template v-slot:fallback>
<div>加载中...</div>
</template>
</Suspense>
</template>
<script>
import { defineAsyncComponent } from 'vue';
const Child = defineAsyncComponent(() => import('./Child.vue'))
export default {
components: {
Child
}
}
</script>
五、其他
1. 全局api
vue2 ===> vue3
Vue.config.xxx ===> app.config.xxx
Vue.component ===> app.component
Vue.mixin ===> app.mixin
Vue.use ===> app.use
Vue.prototype ===> app.config.globalProperties