setup 内部写法
定义数据
-
死数据,不可以修改之类的,但是可以展示视图层。
let str = '1'; -
响应式数据 : ref
【在使用的时候需要 : x.value】
3.响应式数据 : reactive
在使用的时候需要 : 不像ref一样,【不需要.value】
reactive 只能写【对象或者数组】
Vue2 和 Vue3数据拦截不同的点
Vue2.x ==> Object.defineProperty
Vue3.x ==> new Proxy
toRefs
解构==》响应式数据
let obj = reactive({
name:'张三',
age:20
})
let { name,age } = toRefs( obj );
computed
computed有两种写法
1> let changeStr = computed(()=>{
return str.value;
})
2> let changeStr = computed({
get(){
return str.value;
},
set( val ){
str.value = val;
}
})
watch
1> 监听某一个数据
watch( str , (newVal,oldVal)=>{
console.log( newVal,oldVal);
})
2> 同时监听多个数据
watch( [ str , num ] , (newVal,oldVal)=>{
console.log( newVal,oldVal);
})
3> 初始化监听
watch( num , (newVal,oldVal)=>{
console.log( newVal,oldVal);
},{
immediate:true
})
4> 监听对象
watch( obj , (newVal)=>{
console.log( newVal )
},{
immediate:true,
})
5> 监听对象某一个key,并且深度监听
watch( ()=>obj.m , (newVal,oldVal)=>{
console.log( newVal,oldVal )
},{
immediate:true,
deep:true
})
6. 立即执行监听函数
watchEffect(()=>{
console.log( str.value )
})
7. 监听路由
let router = useRouter();
watch( ()=>router.currentRoute.value,( newVal )=>{
console.log( newVal );
},{
immediate:true
})
vue-router
vue-router : router.vuejs.org/zh/api/
tag属性去除了
<router-link to='/about' tag='div'>跳转到关于我们</router-link>
写法问题
let router = useRouter(); ===> this.$router
let route = useRoute(); ===> this.$route
导航守卫
全局路由守卫
beforeEach(to, from, next) 全局前置守卫,路由跳转前触发
beforeResolve(to, from, next) 全局解析守卫 在所有组件内守卫和异步路由组件被解析之后触发
afterEach(to, from) 全局后置守卫,路由跳转完成后触发
路由独享守卫
beforeEnter(to,from,next) 路由对象单个路由配置 ,单个路由进入前触发
组件路由守卫
beforeRouteEnter(to,from,next) 在组件生命周期beforeCreate阶段触发
beforeRouteUpdadte(to,from,next) 当前路由改变时触发
beforeRouteLeave(to,from,next) 导航离开该组件的对应路由时触发
生命周期
选项式 API 【 beforeCreate ... 】
setup 组合式API
注意:没有beforeCreate和created 其他生命周期要使用前面加"on" 例如:onMounted
组件
父传子
1. 父
<template>
<div>
<List :msg='msg'></List>
</div>
</template>
<script setup>
import List from '../components/List.vue'
let msg = ref('这是父传过去的数据');
</script>
2. 子
<template>
<div>
这是子组件 ==> {{ msg }}
</div>
</template>
<script setup>
defineProps({
msg:{
type:String,
default:'1111'
}
})
</script>
子传父
子:
<template>
<div>
这是子组件 ==> {{ num }}
<button @click='changeNum'>按钮</button>
</div>
</template>
<script setup lang='ts'>
let num = ref(200);
const emit = defineEmits<{
(e: 'fn', id: number): void
}>()
const changeNum = ()=>{
emit('fn',num)
}
</script>
父:
<template>
<div>
<List @fn='changeHome'></List>
</div>
</template>
<script setup>
import List from '../components/List.vue'
const changeHome = (n)=>{
console.log( n.value );
}
</script>
v-model传值
父:
<List v-model:num='num'></List>
<script setup>
import List from '../components/List.vue'
let num = ref(1);
</script>
子:
const props = defineProps({
num:{
type:Number,
default:100
}
})
const emit = defineEmits(['update:num'])
const btn = ()=>{
emit('update:num',200);
}
兄弟组件之间的传值
1》下载安装
npm install mitt -S
2》plugins/Bus.js
import mitt from 'mitt';
const emitter = mitt();
export default emitter;
3》A组件
emitter.emit('fn',str);
4》B组件
emitter.on('fn',e=>{
s.value = e.value;
})
插槽
匿名插槽
父:
<A>
这是xxxxx数据
这是yyyyy数据
</A>
子:
<header>
<div>头部</div>
<slot></slot>
</header>
<footer>
<div>底部</div>
<slot></slot>
</footer>
具名插槽
父:
<A>
<template v-slot:xxx>
这是xxxxx数据
</template>
<template v-slot:yyy>
这是yyyyy数据
</template>
</A>
***简写:<template #xxx>
子:
<header>
<div>头部</div>
<slot name='xxx'></slot>
<slot name='yyy'></slot>
</header>
<footer>
<div>底部</div>
<slot name='xxx'></slot>
</footer>
作用域插槽
父:
<template v-slot='{data}'>
{{ data.name }} --> {{ data.age }}
</template>
简写:<template #default='{data}'>
子:
<div v-for='item in list' :key='item.id'>
<slot :data='item'></slot>
</div>
动态插槽: 说白了就是通过数据进行切换
父:
<template #[xxx]>
这是xxxxx数据
</template>
<script setup>
let xxx = ref('xxx');
</script>
Teleport : 传送
<teleport to='#container'></teleport>
<teleport to='.main'></teleport>
<teleport to='body'></teleport>***必须传送到有这个dom的内容【顺序】
动态组件
<component :is="动态去切换组件"></component>
异步组件
***提升性能
vueuse : vueuse.org/core/useint…
使用场景1
组件按需引入:当用户访问到了组件再去加载该组件
<template>
<div ref='target'>
<C v-if='targetIsVisible'></C>
</div>
</template>
<script setup>
import { useIntersectionObserver } from '@vueuse/core'
const C = defineAsyncComponent(() =>
import('../components/C.vue')
)
const target = ref(null);
const targetIsVisible = ref(false);
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }]) => {
if( isIntersecting ) {
targetIsVisible.value = isIntersecting
}
},
)
</script>
使用场景2
<Suspense>
<template #default>
<A></A>
</template>
<template #fallback>
加载中...
</template>
</Suspense>
<script setup>
const A = defineAsyncComponent(() =>
import('../components/A.vue')
)
</script>
打包分包处理
npm run build打包完成后,异步组件有单独的js文件,是从主体js分包出来的
Mixin : 混入
是什么:来分发 Vue 组件中的可复用功能
setup写法
mixin.js
import { ref } from 'vue'
export default function(){
let num = ref(1);
let fav = ref(false);
let favBtn = ()=>{
num.value += 1;
fav.value = true;
setTimeout(()=>{
fav.value = false;
},2000)
}
return {
num,
fav,
favBtn
}
}
组件:
<template>
<div>
<h1>A组件</h1>
{{ num }}
<button @click='favBtn'>
{{ fav ? '收藏中...' : '收藏' }}
</button>
</div>
</template>
<script setup>
import mixin from '../mixins/mixin.js'
let { num , fav , favBtn } = mixin();
</script>
选项式api写法
mixin:
export const fav = {
data () {
return {
num:10
}
},
methods:{
favBtn( params ){
this.num += params;
}
}
}
组件:
<template>
<div>
<h1>A组件</h1>
{{ num }}
<button @click='favBtn(1)'>按钮</button>
</div>
</template>
<script type="text/javascript">
import { fav } from '../mixins/mixin.js'
export default{
data () {
return {
str:'你好'
}
},
mixins:[fav]
}
</script>
Provide / Inject ==> 依赖注入
提供:
<script setup>
provide('changeNum', num );
</script>
注入:
<template>
<div>
<h1>B组件</h1>
{{ bNum }}
</div>
</template>
<script setup>
const bNum = inject('changeNum');
</script>
Vuex
state:
let num = computed( ()=> store.state.num );getters:
let total = computed( ()=> store.getters.total );mutations:
store.commit('xxx')actions:
store.dispatch( 'xxx' )modules:
和之前的版本使用一样
Vuex持久化存储【插件】
1. npm i vuex-persistedstate -S
2. import persistedState from 'vuex-persistedstate'
3. export default createStore({
modules: {
user
},
plugins:[persistedState({
key:'xiaoluxian',
paths:['user']
})]
});
Pinia
Vuex和pinia的区别
参考网址: github.com/vuejs/rfcs/…
- pinia没有mutations,只有:state、getters、actions
- pinia分模块不需要modules(之前vuex分模块需要modules)
- pinia体积更小(性能更好)
- pinia可以直接修改state数据
pinia使用
官方网址:pinia.vuejs.org/
pinia持久化存储
setup语法糖插件
解决import { ref , reactive ... } 引入的问题
下载安装
npm i unplugin-auto-import -D
在vite.config.js中进行配置
import vue from '@vitejs/plugin-vue';
//引入插件
import AutoImport from 'unplugin-auto-import/vite';
const path = require('path');
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports:['vue','vue-router']
})
],
resolve: {
// 配置路径别名
alias: {
'@': path.resolve(__dirname, './src'),
},
},
});