定义变量
ref定义 基本类型 对象类型 解构赋值(需.value)
reactive 对像类型 解构赋值失去响应性
javescript
ref
const num = ref(0)
num.value =
const stringName = ref('111')
const isType = ref(true)
javescript
reactive
const num = reactive({name:'123',age:3})
num.name num.age
若是想把{name:'345',age:120} 赋值给num
Object.assign('num',{name:'345',age:120})
或者
toRefs使reactive中的值都转换成单个ref对象具有响应式
let {name,age} = toRefs(num) 转换成的是 let name = ref('') let age = ref()
解构
toRefs 是把响应式的东西拿出来 在设置成响应式的
toRef 某个属性转成具有响应式的属性
computed计算属性
computed 有缓存 只读不可修改
javescript
import { ref, computed } from 'vue';
const message = ref('Hello');
const reversedMessage = computed(() => {
return message.value.split('').reverse().join('');
});
如果想要修改某个值 需要使用 get set 方法进行修改
javascript
<template>
<div>
<p>Full name: "{{ fullName }}"</p>
<input v-model="fullName" />
</div>
</template>
import { ref, computed } from 'vue';
const firstName = ref('John');
const lastName = ref('Doe');
const fullName = computed({
get() {
return firstName.value + ' ' + lastName.value;
},
set(newValue) {
[firstName.value, lastName.value] = newValue.split(' ');
}
});
</script>
watch
watch 只能监听ref 定义的基本类型和对象类型数据
watch监听基本类型
watch(sum,(v,o)=>{}) watch
监听对象类型的话 监视的是对象的地址值 若想监听到对象内部属性的变化 开启深度监听
watch(person,(n,o)=>{},{deep:true})
watch 监听 reactive 定义的对象 默认是 开启深度监听的 是不能关闭的
let person = reactive({
name:'111',car:{car1:'1',car2:'2'}
})
watch(()=>person.name) 监听对象中的对象
watch(person.car,(new,val)=>{}) 监听c1 c2 可用
watch(()=>person.car,(new,val)=>{}) 监听整个car可用
watch(()=>person.car,(new,val)=>{},{deep:true}) 监听整个car c1 c2 都可用
监听的如果是对象中的属性 使用函数式
若是对象监听的是地址值 需关注对象内部 需要手动开启深度监听
watch 监听多个变量的时候
watch([a,b],(val)=>{ 其中 value是[a的最新值,b的最新值]
let [a1,b1] = value 解构赋值
})
watchEffect
watchEffect 不用写监视谁 直接写回调 立即运行一个函数 同时 响应式的追踪其依赖 并在依赖更改时 重新执行该函数
watchEffect(()=>{
if(a.value)
})
watch 对比watchEffect
都能监听响应式数据的变化,不同的是监听数据变化的方式不同 watch 要明确指出监视的数据 watchEffect 不用明确指出监视的数据 函数中用到哪些属性那就监视哪些属性
vue3中的执行顺序
先执行子组件的mounted 再执行父组件的mounted App.vue 是最后执行的
hook 封装
hook类似vue2中的mixin
具体用法
hook/user.ts
export functiion qwe(){
...属性 方法 函数
return {方法 属性 函数}
}
使用
import qwe from '@/hook/user'
const {方法,属性} = qwe()
vue-router
1 安装
npm install vue-router
2 创建路由配置文件
src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '.../views/Home.vue';
import About from '.../views/About.vue';
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
3 main.js中使用
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
const app = createApp(App);
app.use(router);
app.mount('#app');
4 路由的基本使用
javescript
路由占位符
<router-link to="/">Home</router-link> 跳转区
<router-link to="/about">About</router-link> 展示区
<router-view></router-view>
javescript
组合式 API 访问
import { useRouter, useRoute } from 'vue-router';
export default {
setup() {
const router = useRouter();
const route = useRoute();
// 路由跳转
router.push('/about');
let {query} = toRefs(router) 路由携带参数解构 都变成响应式的
let {params} = toRefs(router) 路由携带参数解构 都变成响应式的
// 获取路由参数
console.log(route.params.id);
}
};
全局前置守卫
javescript
router.beforeEach((to, from, next) => {
if (to.path === '/admin' && !isAuthenticated) {
next('/login');
} else {
next();
}
});
组件内守卫
javescript
export default {
beforeRouteEnter(to, from, next) {
next(vm => {
// 访问组件实例
});
}
};
嵌套路由 配置子路由
javescript
const routes = [
{
path: '/user',
component: UserLayout,
children: [
{ path: 'profile', component: UserProfile },
{ path: 'settings', component: UserSettings }
]
}
];
路由的props
javescript
const routes = [
{
path: '/user/:id/:title/:content?', 添加?时传不传都行
component: UserLayout,
法1 props:true 将路由收到的原有params 参数作为props 传给路由组件 只对params 有效
法2 props(route){ 函数写法 可以自己决定 将什么作为props 传给路由组件
return route.query
}
法3 props:{a:'',b:'',c:''} 对象的写法 可以自己决定将什么作为props 传给组件
}
];
在user页面 props:true 的页面
defineProps(['id','title','content'])
基础导航
javescript
router.push('/about');
router.replace('/home');
router.go(-1); // 后退一页
router.push({ name: 'user', params: { id: 123 } });
router.push({ path: '/user', query: { sort: 'asc' } });
history hash模式
history url比较美观 没有 #号 项目上线时需要服务端配合处理路径问题 否则刷新404问题
大致相关配置
location / {
root:'/root/XXXXXX'
index index.html
try_files
uri uri/ index.html
}
hash 模式 兼容性更好 SEO 优化较差
const router = createRouter({
history: createWebHashHistory(),
routes
});
数据传递
方式1 总线 mitt 接收数据 提前绑定好事件(提前订阅消息) 提供数据:在合适得时候触发事件(发布)
utils/emitter.ts
javescript
import mitt from 'mitt'
export mitt()
或者
const emitter = mitt() 调用mitt得emitter emitter能绑定事件 触发事件
export default emitter
javescript
使用
import emitter from '@/utils/emitter.ts'
emitter.on('test',(v)=>{}) 绑定事件
emitter.off('test')解除绑定
emitter.emit('test')触发事件
emitter.all.clear() 解除所有函数绑定
在组件卸载时解绑事件 emitter.off('test')解除绑定
方式2
$attrs 是什么
父组件传递给子组件但未被声明为 props 的属性
包括 HTML 属性、自定义属性、DOM 事件监听器
不包含:已声明的 props class 和 style(在 Vue 3 中它们有单独的处理机制)
用于实现当前组件的父组件向当前组件的子组件通信(祖-->孙)
所有父组件向子组件传递的数据 接收了 会存在props中 没接收的都在attrs中 $attrs中会包含所有未接收的对象
javescript
<!-- Parent.vue -->
<template>
<ChildComponent
title="父组件标题"
data-id="123"
@custom-event="handleEvent"
class="parent-class"
/>
</template>
<!-- ChildComponent.vue -->
<template>
<div>
<!-- 将未声明的属性透传给孙子组件 -->
<GrandChild v-bind="$attrs" />
</div>
</template>
<script setup>
// 只声明了 title 作为 prop
defineProps(['title'])
</script>
<!-- GrandChild.vue -->
<template>
<div>
<!-- 将接收到的属性绑定到根元素 -->
<div v-bind="$attrs">孙子组件</div>
</div>
</template>
结果 title 被 ChildComponent 作为 prop 接收
data-id 和 @custom-event 透传到 GrandChild
GrandChild 的根元素会获得:data-id="123" 和 custom-event 监听器
Vue 3 中的变化(对比 Vue 2)
特性
Vue 2 包含内容 普通属性 class/style 包含在 attrs 中 事件监听器 在 listeners 中 透传方式 需要同时绑定 attrs 和 listeners
Vue 3 包含内容 属性 + 事件监听器 class/style 不包含在 attrs 中 事件监听器 合并到 attrs 中 透传方式 只需绑定 $attrs
方式3
$refs
- 操作子组件数据: 一旦获取到子组件的实例,父组件可以修改子组件暴露的变量值,实现父子组件间的直接数据交换。
- 批量处理子组件:$refs 可以用于同时获取多个子组件的实例,从而一次性操作多个子组件的数据,这对于批量更新非常有用。
- 访问DOM元素: 除了组件实例,$refs也可以用来获取原生DOM元素的引用,使得开发者可以直接操作DOM元素的属性和方法。
$parent
1.访问父组件实例:$parent允许子组件直接访问其父组件的实例,这为子组件提供了一种方式来调用父组件的方法或修改父组件的数据。
2.破坏封装性
虽然$parent提供了强大的功能,但它也可能导致组件间的紧耦合,破坏了组件的封装性和复用性。因此,官方推荐使用props和自定义事件来实现父子组件间的通信。
3.defineExpose使用
在Vue3中,为了安全地暴露父组件的数据和方法给子组件,可以使用defineExpose宏,这是一种更可控且类型友好的方式。
4.限制使用场景
由于$parent可能导致代码难以维护和理解,它通常不建议作为首选的通信方式,特别是在大型应用中。
javescript
父组件
<template>
<div class="father">
<h4>父组件</h4>
<h4>父亲的房:{{ house }}</h4>
<button @click="changeCar">修改子的车</button>
<son ref="s"/>
</div>
</template>
<script setup lang="ts" name="father">
import { ref } from "vue";
import son from "../components/son.vue";
let s = ref()
let house = ref('檀宫')
function changeCar(){
s.value.car = '奔驰'
}
//暴露属性
defineExpose({house})
</script>
子组件
<template>
<div class="son">
<h4>子组件</h4>
<h4>子的汽车:{{ car }}</h4>
<button @click="changeHouse($parent)">传输数据给父</button>
</div>
</template>
<script setup lang="ts" name="father">
import { ref } from "vue";
let car = ref('宝马')
function changeHouse(parent:any){
parent.house = '汤臣一品'
}
defineExpose({car})
</script>
批量修改相关ts
javescript
父组件中 @click= getA($refs)
function getA(refs:{[key:string]:any}){ [key:string] 定义数据中包含key是string类型 :any 值any 若使用object 会报类型错误
for(let key in refs){
refs[key].book +=3 refs[key]里面得值不定 属性名不定 不能用object定义类型
}
}
方式4
provide inject 祖到孙 孙到祖
javescript
具体使用
发送
import {provide} from 'vue'
provide('名','值')
实现
let money = ref(0)
const updateMoney = (v:number)=>{}
provide('名',{money,updateMoney}) money 必须传递得是响应式对象 updateMoney函数
接收
import {inject} from 'vue'
let x = inject('名') 或 let x = inject('名','默认值') 或 let x = inject('名',{brand:未知,price:0})
实现接收
inject('名',{money:0,updateMoney:(x:num)=>{}})
插槽
javescript
默认插槽
父组件
<category >
<span>123</span>
</category>
子组件category.vue
<div>
<slot></slot>
</div>
javescript
具名插槽 name v-slot
父组件
<category >
<template v-slot:'s1'>
<span>123</span>
</template>
简写
<template #s1>
</template>
</category>
子组件category.vue
<div>
<slot name='s1'></slot>
</div>
javescript
作用域插槽 数据在子组件中 但是结构由父组件决定
父组件
<category >
<template v-slot='params' || v-slot='params.games1' || v-slot={games1}>
<span>{{ params.games1 || games1 }}</span>
</template>
</category>
子组件category.vue
<div>
<slot :games1='games'></slot> :games1='games' 子组件传递数据
</div>
作用域插槽也可以有名字
<slot name='qwe' :games1='games'></slot>
<template v-slot:qwe='params'>{{params.games1}}</template>
其他
shallowRef 只处理第一层的响应式
shallowReactive 浅层次的响应式 只改第一层
readonly 只读
shallowReadonly 浅层次第一层只读
let sum1 = ref(0)
let sum2 = readonly(sum1)
sum2不可直接修改 对数据的保护
readonly(sum1) 响应式对象通过改变sum1修改sum2
toRow 原始数据 函数响应式 不会触发视图更新 用于获取一个响应式对象的原始对象 收到的是普通对象
markRow 标记一个对象 使其永远不会变成响应式的
customRef 自定义Ref
javescript
let initValue = '123'
let msg = customRef((track,trigger)=>{
return {
get(){
track() 持续关注一旦变化就会更新
return initValue
},
set(value){
initValue = value
trigger() 通知vue数据变化
}
}
})
Teleport 是 Vue3 提供的一个内置组件,它可以将组件的内容传送到 DOM 树的任何位置,而不受组件层级的限制。这在处理模态框、通知、弹出菜单等需要突破组件层级限制的场景中特别有用。
javescript
<template>
<teleport to="body">
<!-- 这里的内容会被传送到 body 标签下 -->
<div class="modal">
<!-- 模态框内容 -->
</div>
</teleport>
</template>
原文链接:https://blog.csdn.net/qq_34645412/article/details/145370022
Suspense 是 Vue 3 中用于处理异步组件加载的内置组件,它允许在等待异步组件时显示备用内容
javescript
<template>
<Suspense>
<!-- 默认插槽:显示主要内容 -->
<template #default>
<AsyncComponent />
</template>
<!-- fallback 插槽:加载时显示备用内容 -->
<template #fallback>
<div>加载中...</div>
</template>
</Suspense>
</template>
app.component('hello',hello) 全局组件
app.config.globalProperties.x = '9' 全局属性
如果要给项目添加整体灰调 filter:saturate(0)滤镜 饱和度为0 灰色
自定义指令
app.directive('beauty',(element,{value})=>{
element.innerText += value
element.style.color = 'green'
})
< p v-beauty='sun'>开心< /p>
app.mount('') 挂载
app.unmount() 卸载
app.use()安装插件
vue2与vue3 区别
v-enter 修改为了 v-enter-from
v-leave 修改为了 v-leave-from
v-if v-for 使用优先级发生改变 2 不能同时使用v-if v-for v-if优先级低 v-for 优先级高 3 v-if优先级高于v-for
移除了on off once 方法 filter children propert
event 对原生事件 event就是事件对象能.target
对自定义事件 $event就是触发事件时所传递的数据 不能.target
v-model
javescript
v-model 用于html标签
< input type='text' v-model='name' />
原理 <input :value='name' type='text' @input="name=(<HTMLInputElement>$event.target.value)">
v-model 用于组件标签
<childrenCom v-model="name" />
父级
<script setup>
import { ref } from 'vue'
const title = ref('默认标题')
const content = ref('这里是内容')
</script>
<template>
<CustomEditor v-model:title="title" v-model:content="content" />
<p>标题:{{ title }}</p>
<p>内容:{{ content }}</p>
</template>
CustomEditor.vue
<script setup>
import { defineProps, defineEmits } from 'vue'
defineProps(['modelValue', 'modelModifiers', 'title', 'content'])
const emit = defineEmits(['update:title', 'update:content'])
</script>
<template>
<div>
<input
:value="title"
@input="event => emit('update:title', event.target.value)"
placeholder="编辑标题"
/>
<textarea
:value="content"
@input="event => emit('update:content', event.target.value)"
placeholder="编辑内容"
></textarea>
</div>
</template>
详细链接 :https://blog.csdn.net/2301_79858914/article/details/143828284