vue3.2 blog.vuejs.org/posts/vue-3…
重点: vue3为何放弃defineProperty,使用Proxy
还记得vue经常会出现一个问题 那就是数据改变但是视图没有改变 Proxy就是从这个角度去改变的也可以从这里抓起
创建项目
创建项目命令使用 NPM:
$ npm init vite@latest
使用 Yarn:
$ yarn create vite
使用 PNPM:
$ pnpm create vite
vite 最大的有点就是不用return data 或者setData
<script setup lang="ts"></script> 这里的setup已经做了处理 同时引入组件无需注册
解决跨域
常规操作解决跨域问题 vite.config.ts
export default defineConfig({
plugins: [vue()],
server:{
proxy:{
'/api':{
target:'https://c.m.163.com',
changeOrigin:true,
rewrite:(path)=>path.replace(/^\/api/,'')
}
}
}
})
reactive ref toRefs
需要用的vue页面引入
reactive 和 ref 可以理解成vue中的初始化data onMounted 跟vue的mounted一样注意vue3 生命周期发生改变。
toRefs 结构出变量在dom上方便使用不用data.msg而是可以直接使用msg
import { onMounted, reactive, toRef, toRefs } from 'vue'
import axios from 'axios'
// 定义初始数据 reactive
const data = reactive({
name:'test',
type:1,
areaTree: [],
chinaDayList: [],
chinaTotal: {},
lastUpdateTime: "",
overseaLastUpdateTime: ""
})
//vue3.0 生命周期中请求接口
onMounted(() => {
axios().then(res=>{
data.name = res.data.data.name
})
})
// 主要作用就是省略调了data.type之类的写法 在html里面直接{{type}}
const {chinaTotal,type} = toRefs(data)
点击事件
<div @click="changeNumber(1)">我点击了1</div>
<div @click="changeNumber(2)">我点击了2</div>
//点击的写法
const changeNumber = (type:number)=>{
data.type = type
}
vite 的改写 注意定义类型和引入方法有兴趣可以参照 没有可以直接无视查看组件通讯
创建type文件index.ts
interface IData{
name:string,
type:Number,
areaTree:any[],
chinaDayList: any[],
chinaTotal: object,
lastUpdateTime: string,
overseaLastUpdateTime: string
}
export type {
IData
}
创建pageJS/index.ts
import type {IData} from '../type/index'
import axios from 'axios'
class InitData implements IData {
name: string = ""
type: Number = 1
areaTree: any[] = []
chinaDayList: any[] = []
chinaTotal: object = {}
lastUpdateTime: string =""
overseaLastUpdateTime: string=""
}
// 逻辑层使用的地方直接getData(data)
const getData = (data:InitData)=>{
axios('/api/ug/api/wuhan/app/data/list-total?t=330415245809').then(res=>{
console.log(res,"es");
data.areaTree=res.data.data.areaTree
data.chinaDayList=res.data.data.chinaDayList
data.chinaTotal=res.data.data.chinaTotal
data.lastUpdateTime=res.data.data.lastUpdateTime
data.overseaLastUpdateTime=res.data.data.overseaLastUpdateTime
})
}
export {
InitData,
getData
}
原页面
import {InitData,getData} from '../pageJS/index'
// const data = reactive({
// name:'test',
// type:1,
// areaTree: [],
// chinaDayList: [],
// chinaTotal: {},
// lastUpdateTime: "",
// overseaLastUpdateTime: ""
// })
const data = reactive(new InitData())
onMounted(() => {
getData(data)
})
组件的使用 vue3 之后引入组件将不需要注册组件可以直接使用
组件通讯
<template>
<!-- 子组件 -->
<child-components :list="list"></child-components>
<!-- 父组件 -->
<div class="child-wrap input-group">
<input
v-model="value"
type="text"
class="form-control"
placeholder="请输入"
/>
<div class="input-group-append">
<button @click="handleAdd" class="btn btn-primary" type="button">
添加
</button>
</div>
</div>
</template>
<script setup>
import { reactive, toRefs, onMounted, ref } from "vue";
import ChildComponents from "./components/child.vue";
const list = ref(["JavaScript", "HTML", "CSS"]);
const value = ref('')
const data = reactive({
name: "ces",
areaTree: [{ id: 0, name: "ces" }],
num: 1,
});
const handleAdd = () => {
list.value.push(value.value)
value.value = ''
}
onMounted(() => {
// 接口使用的地方
});
</script>
defineProps
defineProps 子组件接收父组件传递过来的值
<template>
<ul class="parent list-group">
<li class="list-group-item" v-for="i in props.list" :key="i">{{ i }}</li>
</ul>
</template>
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
list:{
type:Array,
default:()=>[]
}
})
</script>
defineEmits
defineEmits 子组件传父组件
<li class="list-group-item" v-for="i in props.list" :key="i">{{ i }} <button @click="deleteListRow(i,key)">删除</button></li>
deleteListRow 获取到下标
import { defineProps,defineEmits } from 'vue'
const emits = defineEmits(['deleteRow'])
let index = Object.values(props.list).findIndex(item => item == value)
// 传入下标
emits('deleteRow',index)
}
子组件使用
<child-components :list="list" @deleteRow="deleteRow">
const deleteRow = value =>{
console.log('接收子组件传递过来的下标',value);
}
ref + defineExpose
defineExpose 子组件自己暴露给父组件 (无论是对象还是数组或者是对象布尔值等等都可以)
子组件 child.vue
// 子组件
import { ref,defineExpose,reactive } from 'vue'
const aaa = ref('aaa')
defineExpose({
aaa,
})
父组件使用ref
<child-components ref="childRefs"></child-components>
<button @click="exposure">refs子组件暴露给父组件</button>
利用点击事件获取子组件暴露来的值
// 父组件
const childRefs = ref(null)
const exposure = () =>{
console.log(childRefs.value.aaa);
}
provide/inject
provide和inject是Vue中提供的一对API,该API可以实现父组件向子组件传递数据,无论层级有多深,都可以通过这对API实现。
父组件 // provide 不需要经过html
import { reactive, ref,provide } from "vue";
const provideNum = ref('provide传递过来的参数')
provide('provideNum',provideNum.value)
子组件
import { inject } from 'vue'
const injects = inject('provideNum')
console.log(injects,"inject"); // provide传递过来的参数 inject
mitt
Vue3 中没有了 EventBus 跨组件通信,但是现在有了一个替代的方案 mitt.js,原理还是 EventBus
先安装 npm i mitt -S
然后像以前封装 bus 一样,封装一下
import mitt from 'mitt'
const mitts = mitt()
export default mitts
child 子组件
<button @click="mittClick">Child-mitt传值
import mitts from '../../utils/mitt'
const mittClick = () =>{
mitts.emit('handleChange','mitt.emit获取到的值')
}
child2 子组件
import mitts from '../../utils/mitt'
import { onUnmounted,ref} from 'vue'
const mitssName = ref("")
mitts.on('handleChange', (params)=> {
mitssName.value = params
})
// 组件卸载
onUnmounted(()=>{
mitt.off('handleChange',null)
})
vue
和vue2同理vuex没啥改变
// store/index.js
import { createStore } from "vuex"
export default createStore({
state:{ count: 1 },
getters:{
getCount: state => state.count
},
mutations:{
add(state){
state.count++
}
}
})
// main.js
import { createApp } from "vue"
import App from "./App.vue"
import store from "./store"
createApp(App).use(store).mount("#app")
// Page.vue
// 方法一 直接使用
<template>
<div>{{ $store.state.count }}</div>
<button @click="$store.commit('add')">按钮</button>
</template>
// 方法二 获取
<script setup>
import { useStore, computed } from "vuex"
const store = useStore()
console.log(store.state.count) // 1
const count = computed(()=>store.state.count) // 响应式,会随着vuex数据改变而改变
console.log(count) // 1
</script>