Vue3操作
Vue3
集成环境
使用官方脚手架来
-
使用webpack打包工具
vue create 项目名
-
使用vite来打包
npm init vite-app 项目名 npm i cd 项目名 npm run dev
优势:
- 开发环境中,无需打包操作,可以快速冷启动
- 轻量快速的热重载
- 按需编译,不用等待整个引用都加载完成
setup
是vue3的一个新的配置项,值是一个钩子函数
用法
-
直接写配置项
setup()
export default { setup() { } }
-
语法糖的写法
setup
写script标签上<script setup> </script>
返回值
- 返回一个对象,对象中的方法,属性在模板中可以直接使用
- 返回一个渲染函数,可以自定义渲染函数,这时候,模板中内容的会失效
注意
- 尽量不要和vue2混合使用
- vue2配置中可以访问到setup中的属性和方法,但setup中不能访问到vue2中的配置
- 如果有重名冲突,setup优先
- 在setup中不能使用this
- setup不能是一个asyn函数,因为返回的不再是return的对象,而是primise,模板看不到return对象中的属性(后期可以返回一个promise,但要配合suspense和异步组件一起使用)
ref函数
isRef
作用:判断是否是一个Ref对象,返回值是一个布尔值
let price = toRef(person.zhiye,'price')
console.log(isRef(price))
toRef
作用:创建一个ref对象,其value值指向另一个对象的指定属性
let name = toRef(preson,'name')
适用场景:某一个对象的某个属性单独使用,又想要又响应式功能
import {reactive, toRef, toRefs} from 'vue'
let person = reactive({
name: '张三',
id: 1,
age: 34,
zhiye: {
price: 4432,
title:'前端工程师'
}
})
// 用法:传入参数,第一个参数是对象,第二参数是要处理的响应式数据的值(字符串)
let price = toRef(person.zhiye,'price')
let changeprice = () => {
price.value = 10000
// console.log()
}
注意:toRef
包裹的对象如果想要修改,用price.value的方式修改
拓展:toRefs
功能和toRef
类似,不同的是toRefs可以指定多个ref对象(一层)
let {a,b}=toRefs(obj)
// let a = toRef(obj.a) let b = toRef(obj.b) 隐式代码
- toRefs函数接收一个响应式对象作为参数
reactive函数
计算属性
监听属性
watch
监听属性和vue2的用法相似
- 对于监视reactive定义的响应式数据时,oldvalue无法正确获取,强制开始了深度监视(deep的配置失效)
- 监视reactive定义的响应式数据的某一个值时:deep配置有效
<script setup>
import { ref,watch } from 'vue'
let studentId = ref(32)
let studentname = ref('lisi')
watch(studentId,(date)=> {
console.log('改变学生信息')
})
let chang = ()=> {
studentId.value = 33
studentname.value = 'wangwu'
}
</script>
<template>
<div class="student">
<h2>学生学号:{{studentId}} <br> 学生姓名:{{studentname}}</h2>
<button @click="chang">改变学生id号码</button>
</div>
</template>
watchEffect
是一个函数,不用指定某一个属性,监听回调里面用了哪个属性就调用监听哪个属性
和compputed类似,区别
- computed必须要写返回值,更注重的是结果,watchEffect注重的是过程
//setup
import {watchEffect} from 'vue'
watchEffect(()=> {
let x1 = sum.value
console.log('调用了watchEffect')
})
其他API
shallowReactive与shallowRef
- shallowReactive:只处理对象外层属性的响应式(浅响应式)
- shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理
readonly与shallowReadonly
- readonly:让一个响应式数据变为只读(深可读)
- shallowReadonly:让一个响应式变为只读的(浅只读)
toRow和markRow
toRow
- 作用:将响应式数据生成普通对象
markRow
- 作用:标记一个对象,使其永远不会成为响应式
- 应用场景:有些不应该被设置为响应式的,例如复杂的第三方库
- 当渲染的具有不可变的数据源的大列表,跳过响应式可以提高性能
Vue3生命周期
和Vue2类似,但有一些改变
- 将beforeDestory改名为beforeUnmount,destoryed改名为unmounted
- 新增了一个setup生命周期函数,在setup中不能使用this,所以它是在beforecreated之前
onBeforeMount onMounted
onBeforeUpdate onUpdated
onBeforeUnmount onUnmounted
onErrorCaptured
onRenderTracked
onRenderTriggered
内置组件
Fragment
- 在vue2中,必须有一个根标签,但在vue3中,可以不写跟标签,内部会将标签包含在Fragment虚拟元素内
优点:减少层级的嵌套,减少内存占用
Teleport
可以将模板移动到组件外的地方
teleport
组件,用to
属性来指定位置
<template>
<div class="appbig">
<teleport to="body">
<div class="poping">
<button>teleport点击弹窗</button>
</div>
</teleport>
</div>
</template>
注意
- 修改的时候用flag.value来修改,但是模板中使用直接写flag
Suspense
本身底层是用具名插槽实现的,分别名为default
和fallback
,在异步加载组件的时候,如果组件没有加载出来,会先有一个默认模板(模板内容可以是一个组件)
-
引入异步组件
import {defineAsynComponent} from 'vue' const Child = defineAsynComponent(()=> import('./Child.vue'))
-
使用
Suspense
包裹组件,配置default
和fallback
<Suspense>
<template v-slot:default></template>
<template v-slot:fallback></template>
</Suspense>
组件间通信
privide和inject
实现祖孙组件间的通信
-
父组件又
provide
选项来提供数据import {provide} from 'vue' setup() { ... privide('car',car) }
-
子组件用
inject
项目来使用这些数据import {inject} from 'vue' setup() { ... let car = inject('car') }
属性传值
-
父组件用
:
绑定属性 -
子组件要引入
defineProps
,用来接收传来的数据import { defineProps } from 'vue'; let obj = defineProps(['title'])
在模板中用{{obj.title}}
自定义事件
-
引入
defineEmits
-
调用
let emit = defineEmits() emit('myclick')
在哪里定义的自定义事件,就在哪里写自定义调用的函数
// 父组件 app.vue
<script setup>
import Zidingyi from "./components/zidingyi.vue";
// import Poping from './components/Poping.vue';
let fn = ()=> {
alert('what 5')
}
</script>
<template>
<div class="appbig">
<!-- <Poping msg="msg数据"></Poping> -->
<Zidingyi @myclick="fn"></Zidingyi>
</div>
</template>
//子组件
<script setup>
import { ref,defineEmits } from 'vue'
let num = ref(0)
let emit = defineEmits()
let add = ()=> {
num.value++
if(num.value==5) {
emit('myclick')
console.log('触发')
}
}
</script>
<template>
<div class="zdy">自定义事件
<h2>{{num}}</h2>
<button @click="add">加一</button>
</div>
</template>
公共配置
实例API(app) | 全局配置(vue) |
---|---|
Vue.config.xxx | app.config.xxxxx |
Vue.config.productionTip | 移除 |
Vue.component | app.component //定义全局组件 |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties //原型链中的东西,放在此配置中,具体使用如下 |
-
设置
app.config.globalProperties.$axios='axios'
-
组件中使用
import {getCurrentInstance} from 'vue' let vc = getCurrentInstance() console.log(vc.proxy.$axios)
注意:getCurrentInstance
只能在组件中的钩子函数中获取实例
网络配置
import axios from 'axios'
axios.defaults.baseURL="http://127.0.0.1:8080/api"
app.config.globalProperties.$axios = axios
配置代理
//vite环境:
proxy: {
'/api': {
target: 'http://127.0.0.1:7001', // 代理的目标地址
rewrite: (path) => path.replace(/^\/api/, '/'), // 路径重写
changeOrigin:true,
// secure: true, // target是否https接口
// ws: true, // target是否代理websockets
}
}
路由配置
下载npm i vue-router
配置路由在router/index.js中,和vue2中类似
main.js中导入挂载
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index.js'
const app = createApp(App)
app.use(router)
app.mount('#app')
数据仓库
vue3中有vuex也有Pinia
这里我们主要学习Pinia
-
下载
npm i pinia
-
在main.js中导入
import {createPinia}from 'pinia' //创建实例并use到app中 app.use(createPinia())
-
创建仓库
//store/car.js import { defineStore } from "pinia"; export const useCar = defineStore('car',{ state: ()=> { return { carname: '大众汽车' } } } )
defineStore(storeid,option):提供给es6使用this
-
storeid:字符串的仓库唯一标识
-
option:state返回的对象为我们要使用的数据
-
state
-
getters:可以当作计算属性使用,当函数用到的属性使用的时候,就会更新
//router/index.js defineStore('car',{ state: ()=> { return: {} }, getters: { age: (state)=> {} } })
-
action:可以异步操作,this可以使用,this为仓库上下文对象
//router/index.js defineStore('car',{ state: ()=> { return: {} }, getters: { age: (state)=> {} }, actions: { tool(){ console.log(this) } } })
getters和action区别
- action可以异步操作
- 统一修改
-
-
-
看具体创建仓库的方式,在组件中导出仓库并时候
//setup import {useCar} from '../store/Car.js' let carInfo = useCar() console.log(carInfo.carname) // 结构赋值的方式 let {carname} = carInfo
-
修改仓库,直接修改(vuex不同)
//setup import {useCar} from '../store/Car.js' let carInfo = useCar() carInfo.carname = '修改为特斯拉汽车'
注意:利用结构赋值的carname修改的数据,不具备响应式的功能
解决方法,可以使用toRefs
//setup import {toRefs} from 'vue' let {carname} = toRefs(carInfo)
批量修改
- carInfo.$patch:修改数据
//setup carInfo.$patch({ carname: '修改为特斯拉汽车', a: '90' //修改的a,原本的仓库不存在 })
- 批量修改的状态刷新一次
- 如果数据不存在,比如上方例子的a,vue3中不会添加a值到仓库中。注意:其他的框架,比如react是会添加的
-
订阅修改:通过patch修改状态时就会触发一次
carInfo.$subscribe((n1,carInfo.carname)=> { //pass })
-
仓库可以使用其他的仓库
//car 仓库使用userinfo仓库跟组件使用方式 import {userinfo} from '../store/userinfo' let store = userinfo()