前言:
当前大家对“vue 列表页跳详情”都比较讲究,小伙伴们都需要知道一些“vue 列表页跳详情”的相关文章。那么小编也在网络上网罗了一些关于“vue 列表页跳详情””的相关知识,希望朋友们能喜欢,朋友们快快来学习一下吧!Vue3相对Vue2的变化:
Vue3对TypeScript支持更友好,不像Vue2,所有属性都放在了this对象上,难以推倒组件的数据类型Vue2大量的API挂载在Vue对象的原型上,难以实现TreeShaking,Vue3可以按需导出。新推出了CompositionAPI,可以把关联代码写在一起更方便的支持了JSXVue3 的 Template 支持多个根标签,Vue 2 不支持对虚拟DOM进行了重写、对模板的编译进行了优化操作23.在vue的template部分,访问ref变量值无需带.value
<footer :style="{ paddingBottom: '0.45rem' }"> <!-- 不要写成 () => shareGuideRef.vaule.show()--> <span @click="() => shareGuideRef.show()">分享</span> </footer> <BaseWxShare ref="shareGuideRef"/>
22.在vue的template部分,无法使用BOM全局变量
错误写法:
<div class="poster-with-card poster-canvas-content" :style="{width: `${screen.width}px`}">
正确写法:
<div class="poster-with-card poster-canvas-content" :style="html2canvasStyle"> <script setup lang="ts"> const html2canvasStyle = { width: `${screen.width}px`, }; </script>
21. 在less中如何使用响应式变量语法
<script>const styleProgressWidth=ref(`${props.finishTarget/props.target*100}%`);</script><style>.foo{ width:v-bind(styleProgressWidth);}</style>
20. 动态class的设置方法
<script setup>import { ref } from 'vue'const msg = ref('Hello World!')</script><template> <h1 :class="'red' ${msg === 'Hello World!' && 'green'}">{{ msg }}</h1> <input v-model="msg"></template><style scoped> .red{ color:red; } .green{ color:green }</style>
19. @eventName="foo" 后面有无括号的差别
这里的eventName指的是vue内置的dom事件
@click有括号:传指定参数@click无括号:默认传event参数18.v-model可以定义多个
<van-list v-model:loading="loading" v-model:error="error" error-text="请求失败,点击重新加载" @load="onLoad"> <van-cell v-for="item in list" :key="item" :title="item" /></van-list>
17. useVModel语法糖
使用useVModel, 子组件就能修改父组件传递的属性值
父组件
<div><! -- --> <ChildComps v-model:visible="visibleFeedbackModal" /></div>
子组件
import { useVModel } from '@vueuse/core'const props = defineProps<{ visible: string;}>();const emit = defineEmits(['update:visible']);// 带有类型定义的写法const emit = defineEmits<{ (e: 'update:visible', params: any): void;}>();const visibleModel = useVModel(props, 'visible', emit);const handleDialogClose = async () => { visibleModel.value = false;};
16. keep-alive用法示例
<template> <router-view v-slot="{ Component }"> <transition> <keep-alive :include="includeList"> <component :is="Component" /> </keep-alive> </transition> </router-view></template><script lang="ts"> export default {name:'AppEntry'} </script><script lang="ts" setup> const router = useRouter(); const includeList = ref(['AuthByManagerList']); router.beforeEach((to, from) => { if (from.path === '/authByManagerResult' && to.path === '/authByManagerList') { // 从客户认证结果页跳列表页,要清除缓存 includeList.value = []; } else if (from.path === '/authByManagerList' && to.path === '/authByManagerDetail') { // 从列表页进入详情页,要缓存列表页 includeList.value = ['AuthByManagerList']; } });</script>
15.computed属性完整写法watch的套路是:既要指明监听的属性,也要指明监听的回调函数。watchEffect的套路是:不需要指明监听的属性,监听中的回调函数用到了那个属性,就监听那个属性。
watchEffect跟computed有点像:
computed注重是计算出来的值,所以必须要有返回值。watchEffect更注重是过程,所以不用写返回值。
const person = reactive({ fistName:"Mr", lastName:"long"}) // 计算属性简写let fullName = computed(()=>{ return person.fistName + '-' + person.lastName})// 计算属性完整写法let fullName = computed({ get(){ return person.fistName + '-' + person.lastName }, set(value){ const newArr = value.split('-') person.fistName = newArr[0] person.lastName = newArr[1] }})
computed 接收参数的语法
<template> <div> <div v-for="(item,index) in arr" :key="index"> {{formatName(item)}} </div> </div> </template>
const formatName = computed(()=>(item)=>`客户经理${item.name},请及时拜访你的客户${item.custName}`);
14.watch和watchEffect的区别watch 是需要传入侦听的数据源,而 watchEffect 是自动收集数据源作为依赖。watch 可以访问侦听状态变化前后的值,而 watchEffect 没有,watchEffect获取的改变后的值。watch 是属性改变的时候执行,当然也可以immediate,而 watchEffect 是默认会执行一次,然后属性改变也会执行。watch监听ref值,不用加.value,watch监听对象的某个属性值时,书写方式是watch([()=>obj.propA],()=>{})
// 情况一监听ref响应式数据 watch(count,(newValue,oldValue)=>{ console.log(newValue,oldValue) },{immediate:true}) // immediate 立即监听// 情况二 监听多个ref响应式数据watch([count,name],(newValue,oldValue) =>{ console.log(newValue,oldValue) // 此时value的数据是数组})// 情况三 监听reactvie响应式数据// 如果watch监听是reactive定义的响应式数据,则无法获取正确的oldValue,且强制开启深度监听。 watch(person,(newValue,oldValue)=>{ console.log(newValue,oldValue) // 两个值一致都是一样的 }) // 情况四 监听reactive定义的响应式数据的某个属性(基础数据类型) watch(()=>person.name,(newValue,oldValue) =>{ console.log(newValue,oldValue) }) // 情况五 监听多个reactive定义的多个响应式数据的属性(基础数据类型) watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{ console.log(newValue,oldValue) }) // 情况六 监听reactive定义的响应式数据的某个属性(复杂数据类型) watch(() => person.class,(newValue,oldValue) =>{ // 此时的class 为 { b:{c:20 } }, 想要监听c值的变化 则需要开启deep深度监听 console.log(newValue,oldValue) },{deep:true})
13. 判断slot命名插槽是否定义,定义才展示
<slot v-if="$slots.customButton" name="customButton"></slot> <Button v-else :type="buttonType" :disabled="disabled" :loading="loading"> <template #icon><UploadOutlined /></template> {{ btnText }} </Button>
12.useSlots用法
父组件
<template> <!-- 子组件 --> <ChildTSX> <!-- 默认插槽 --> <p>I am a default slot from TSX.</p> <!-- 命名插槽 --> <template #msg> <p>I am a msg slot from TSX.</p> </template> </ChildTSX></template><script setup lang="ts"> import ChildTSX from '@cp/context/Child.tsx'</script>
子组件
<script lang="ts" setup>// 注意:这是一个 .tsx 文件import { useSlots } from 'vue'const slots = useSlots()const ChildTSX = ()=>{ // 渲染组件 return () => ( <div> {/* 渲染默认插槽 */} <p>{ slots.default ? slots.default() : '' }</p> {/* 渲染命名插槽 */} <p>{ slots.msg ? slots.msg() : '' }</p> </div> ) }}export default ChildTSX</script>
11. 父子组件通信 props/emit方式
父组件
<template> <Child ref="child" title="用户信息" :index="1" :uid="userInfo.id" :user-name="userInfo.name" @update-age="updateAge" /></template><script lang="ts" setup>import { ref, onMounted } from 'vue'import Child from '@cp/Child.vue'type TMember={ id: number, name: string}const child = ref<typeof Child | null>()const userInfo: TMember = { id: 1, name: 'Petter'}// 父组件调用子组件的方法onMounted(() => child.value?.childMethod)const updateAge = (age: number) => { console.log(age);}</script>
子组件
<template> <p>标题:{{ title }}</p> <p>索引:{{ index }}</p> <p>用户id:{{ uid }}</p> <p>用户名:{{ userName }}</p></template><script lang="ts" setup>import { withDefaults, defineProps, defineEmits, toRefs, defineExpose } from 'vue';const props = withDefaults(defineProps<{ title: string; index: number; uid: number; userName: string;}>(), { userName: 'zhangsan' }); // 复杂类型赋初始值 const props = withDefaults(defineProps<PropsType>(), { value: () => { return { memberList: [], deptList: [], positionList: [], }; }, });const { title, index, uid, userName } = toRefs(props);// 接受子组件传进来的方法const emit = defineEmits(['update-age']);setTimeout(() => { emit('update-age', 22);}, 2000);const childMethod = () => { console.log('我是子组件的方法')}// 子组件暴露方法给父组件defineExpose({ childMethod })</script>
10. 使用ref操作dom
<template> <p ref="msg">留意该节点,有一个ref属性</p></template><script lang="ts" setup>import { onMounted, ref } from "vue";// 定义挂载节点,声明的类型详见下方附表const msg = ref<HTMLElement | null>();// 请保证视图渲染完毕后再执行节点操作 e.g. onMounted / nextTickonMounted(() => { // 比如获取DOM的文本 console.log(msg.value?.innerText);});</script>
9. 给props属性赋初始值
<script lang="ts" setup> import {withDefaults,defineProps} from 'vue'; const props = withDefaults(defineProps<{ btnName: string; noBtn?: boolean; doAction: () => void; classStyle?: string; config:any[]; }>(),{ noBtn:true, // 设置默认值 classStyle:'' config:()=>[], }); const mActionClass=`m-action ${props.classStyle}`;<script>
另外还有两点需要说明一下:
Vue3组件即便用withDefaults设置了默认值, props类型定义属性要设置为可选,否则VSCode插件会有告警提示。vue3中的props在模板中会同步更新,在setup函数中只更新一次。当props值再次发生改变时,在setup中要用watch/watchEffect/computed才能监听到props的变化,如果props某个属性是对象,要设置深度监听,才能监听到变化。8. toRefs和toRef的用途
借助toRefs可以在template部分,直接使用结构后的对象单个键值,写法简洁,却不失响应式。 toRef是转换reactive对象的单个值
<template> <ul class="user-info"> <li class="item"> <span class="key">ID:</span> <span class="value">{{ id }}</span> </li> <li class="item"> <span class="key">name:</span> <span class="value">{{ name }}</span> </li> <li class="item"> <span class="key">age:</span> <span class="value">{{ age }}</span> </li> <li class="item"> <span class="key">gender:</span> <span class="value">{{ gender }}</span> </li> </ul></template><script lang="ts" setup>import { reactive, toRef, toRefs } from "vue";interface Member { id: number; name: string; age: number; gender: string;}// 定义一个reactive对象const userInfo: Member = reactive({ id: 1, name: "Petter", age: 18, gender: "male",});// 结构reactive对象,它的字段全部是ref变量const { id, age, gender } = toRefs(userInfo);const name: string = toRef(userInfo, 'name');// 2s后更新userInfosetTimeout(() => { userInfo.id = 2; userInfo.name = "Tom"; userInfo.age = 20;}, 2000);</script>
用toRefs解构ref定义的对象属性会丢失响应式
import {toRefs} from 'vue';const foo=ref({bar:'xxx'});const {bar}=toRefs(foo);
<template>{{bar}}</template>
7. ref和reactive区别ref可以定义任何类型的数据,但是定义数据和对象时,在script部分使用时,赋值和取值,不如reactive方便reactive只能用于数组,对象类型。ref的本质是通过reactive创建的,ref(10)=>reactive({value:10});reactive的本质是将每一层的数都解析成proxy对象,reactive 的响应式默认都是递归的,改变某一层的值都会递归的调用一遍,重新渲染dom。
<template> <p>{{count}}</p> <button @click="add">加1</button> <p>{{info.name}}</p> <button @click="changeName">改姓名</button></template><script lang="ts" setup>import { reactive, ref } from 'vue';interface Info{ name:string; age:number;}// 响应式基本类型用refconst count = ref<number>(0);// 响应式引用类型用reactiveconst info:Info = reactive({ age: 100,name:'zhangsan' });const add = () => { // 基本类型赋值时,是赋值给value属性 count.value += 1;};const changeName = () => { info.name="lisi";};</script>
6. 路由取值和跳转
<script lang="ts" setup>import { useRoute, useRouter } from 'vue-router';const route = useRoute();const router = useRouter();// 获取路由信息console.log(route.query.id);// 编程式路由跳转const jump = ()=> { router.push({ path: `/about` , query:{id:'xxx}});};</script>
5.jsx语法支持,要借助插件@vitejs/plugin-vue-jsx
<script lang="tsx" setup>const jsxNode = () => { return <div>text</div>;};</script><template> <jsxNode /></template>
vite.config.ts配置
// tsx语法支持import vueJsx from '@vitejs/plugin-vue-jsx';export default { plugins: [vueJsx(),],}
4. shallowReactive, shallowRef, readonly,shallowReadonly,toRaw,markRaw区别
4.1 shallowReactive、shallowRef的之间的区别
复制代码shallowReactive:浅监视shallowRef:不做监视
4.2 readonly和shallowReadonly
readonly:只读属性的数据,深度只读const state2 = readonly(state)shallowReadonly:只读的数据,浅只读的
4.3 toRaw和markRaw
toRaw将代理对象变成普通对象,数据变化,界面不会进行更新const user = toRaw(state);markRaw标记的对象数据,从此以后都不能在成为代理对象了const likes = ['吃','喝'];state.likes = markRaw(likes);
<template> <h4> <button @click="triggerShallowReactiveRender"> 改变第一层才会渲染 </button> </h4> <p>{{ shallowReactiveState.a }}</p> <h4> <button @click="triggerShallowRefRender"> 失去响应式 </button> </h4> <p>{{ shallowRefState.a }}</p> </template><script setup>import { readonly,reactive, shallowReactive, shallowRef, toRaw } from "vue";// shallowRef 与shallowReactive// shallowRef 与shallowReactive创建的是非递归的响应对象,shallowReactive创建的数据第一层数据改变会重新渲染domconst shallowReactiveState = shallowReactive({ a: "initShallowReactiveState", b: { c: "c", },});//如果不改变第一层 只改变其他的数据 页面不会重新渲染,例如:shallowReactiveState.b.c = 2;//改变第一层的数据会导致页面重新渲染const triggerShallowReactiveRender=()=>{ shallowReactiveState.a = "changeShallowReactiveState";}// shallowRef创建的对象没有响应式特性const shallowRefState = shallowRef({ a: "initShallowRefState", b: { c: "c", },}); const triggerShallowRefRender=()=>{ //失去响应式--除非对整个对象重新赋值或者使用triggerRef(shallowRefState)触发页面更新 shallowRefState.a = "changeShallowRefState";}// toRaw ---只修改数据不渲染页面var obj = { name: "test" };var toRawState = reactive(obj);var raw = toRaw(toRawState);//并不会引起页面的渲染,而obj.name,toRawState.name的值均已改变setTimeout(()=>raw.name = "zs",2000);// 不允许修改对象的值 const readonlyState = readonly({a:1,b:2});// 赋值会引起警告readonlyState.a=2;</script>
3. 生命周期函数
vue2和vue3生命周期对比
beforeCreate -> 使用 setup()created -> 使用 setup()beforeMount -> onBeforeMountmounted -> onMountedbeforeUpdate -> onBeforeUpdateupdated -> onUpdatedbeforeDestroy -> onBeforeUnmountdestroyed -> onUnmountederrorCaptured -> onErrorCaptured
<template> <div class="home"> <p>{{ count }}</p> <p>{{ state.a }}</p> <button @click="add">加1</button> </div></template><script lang="ts" setup>import { ref, reactive, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onErrorCaptured, onRenderTracked, onRenderTriggered, onActivated, onDeactivated,} from "vue";const count = ref(1);const state = reactive({ a: 10 });const add = () => { count.value += 1; state.a = state.a + 1;};onBeforeMount(() => { console.log("onBeforeMount");});onMounted(() => { console.log("onMounted");});onBeforeUpdate(() => { console.log("onBeforeUpdate");});onUpdated(() => { console.log("onUpdated");});onBeforeUnmount(() => { console.log("onBeforeUnmount");});onUnmounted(() => { console.log("onUnmounted");});onErrorCaptured((evt) => { console.log("onErrorCaptured", evt);});// 只执行一次,有几个响应式api,执行几次onRenderTracked((evt) => { console.log("onRenderTracked", evt);});// 行为如同onUpdated,每次有数据更新都会执行onRenderTriggered((evt) => { console.log("onRenderTriggered", evt);});// keep-alive要用到的函数onActivated(() => { console.log("onActivated");});onDeactivated(() => { console.log("onDeactivated");});</script>
2.context的属性有哪些?
setup(props, context) { const {attrs,slots,parent,root,emit,refs}=context; return { // ... }}
1. 获取更详细的报错信息
app.config.errorHandler = (err, vm, info) => { console.log('[全局异常]', err, vm, info)}
作者:去伪存真
链接:
标签: #vue 列表页跳详情