当前位置: 首页 > news >正文

Vue学习Ⅳ

Vuex案例

index.js

//该文件用于创建Vuex中最为核心的store
import Vue from "vue";
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)//准备actions——用于响应组件中的动作
const actions = {jia(context,value){context.commit('JIA',value)},jian(context,value){context.commit('JIAN',value)}
}
//准备mutations——用于操作数据(state)
const mutations = {JIA(state,value){state.sum += value},JIAN(state,value){state.sum -= value},
}
//准备state——用于存储数据
const state = {sum:0 //当前的和
}//创建并暴露store
export default new Vuex.Store({actions,mutations,state,
})

Count.vue

<template><div class="category"><h1>当前求和为:{{$store.state.sum}}</h1><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment">+</button><button @click="decrement">-</button><button @click="incrementOdd">当前求和为奇数再加</button><button @click="incrementWait">等一等再加</button></div>
</template><script>
export default {name:'Count',data() {return {n:1,}},methods: {increment(){this.$store.dispatch('jia',this.n)},decrement() {this.$st/ore.dispatch('jian',this.n)},incrementOdd(){if(this.$store.state.sum % 2){this.$store.dispatch('jia',this.n)}},incrementWait() {setTimeout(()=>{this.$store.dispatch('jia',this.n)},500)}},mounted() {// console.log('Count',this)// console.log('Count store:', this.$store) // 检查组件中的 store}
}
</script><style lang="css">button{margin-left: 5px;}
</style>

模板里不用写this,脚本里前要加this。

getters配置项

1、概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。

2、在store/index.js中追加getters配置

//准备getters——用于将state中的数据进行加工
const getters = {bigSum(state){return state.sum*10}
}//创建并暴露store
export default new Vuex.Store({actions,mutations,state,getters,
})

3、组件Count.vue中读取数据:$store.getters.bigSum

<h3>当前求和放大10倍为:{{ $store.getters.bigSum }}</h3>

简单化模板语法

模板里最好用简洁的语法,如

<h1>当前求和为:{{$store.state.sum}}</h1>

简化为

<h1>当前求和为:{{sum}}</h1>

在脚本里需要使用计算属性,追加如下

computed:{sum(){return this.$store.state.sum}},

以上还是太复杂

mapState mapGetters

import { mapGetters, mapState } from 'vuex'

computed计算属性中追加以下内容,可在模板内直接使用sum,school等属性。

        //借助mapState生成计算属性,从state中读取数据。(对象写法)...mapState({he:'sum',xuexiao:'school',xueke:'subject'}),//借助mapState生成计算属性,从state中读取数据。(数组写法)...mapState(['sum','school','subject']),//借助mapGetters生成计算属性,从getters中读取数据。(对象写法)...mapGetters({bigSum:'bigSum'}),//借助mapGetters生成计算属性,从getters中读取数据。(数组写法)...mapGetters(['bigSum']),

mapMutations

mapMutations 是 Vuex 提供的辅助函数,它像一个快捷键生成器,让你能直接在组件中调用 mutations(状态修改器),而不用每次都写 this.$store.commit('mutation名') 这种冗长的代码。

// 传统写法
this.$store.commit('increment')// 使用 mapMutations 后
this.increment() // 直接调用!

mapActions

mapActions 是 Vuex 中用于简化组件与 Vuex actions 交互的一个重要工具,它使得组件能够以一种简洁的方式调用 Vuex 中定义的 actions。

//程序员亲自写的方法incrementOdd(){if(this.$store.state.sum % 2){this.$store.dispatch('jia',this.n)}},incrementWait() {setTimeout(()=>{this.$store.dispatch('jia',this.n)},500)},//借助mapActions生成对应的方法,方法中会调用dispatch去联系actiosn(对象写法)
...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

多组件共享数据

Count.vue

<template><div class="category"><h1>当前求和为:{{he}}</h1><h3>当前求和放大10倍为:{{ bigSum }}</h3><h3>我在{{ xuexiao }},学习{{ xueke }}</h3><h3>下方组件的总人数是:{{ personList.length }}</h3><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment(n)">+</button><button @click="decrement(n)">-</button><button @click="incrementOdd(n)">当前求和为奇数再加</button><button @click="incrementWait(n)">等一等再加</button></div>
</template><script>
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'export default {name:'Count',data() {return {n:1,}},methods: {//借助mapMutuions生成对应的方法,方法中会调用commit去联系mutitaions(对象写法)...mapMutations({increment:'JIA',decrement:'JIAN'}),//借助mapActions生成对应的方法,方法中会调用dispatch去联系actiosn(对象写法)...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})},computed:{//借助mapState生成计算属性,从state中读取数据。(对象写法)...mapState({he:'sum',xuexiao:'school',xueke:'subject',personList:'personList'}),//借助mapGetters生成计算属性,从getters中读取数据。(对象写法)...mapGetters({bigSum:'bigSum'}),},mounted() {}
}
</script><style lang="css">button{margin-left: 5px;}
</style>

Person.vue

<template><div><h1>人员列表</h1><h3>Count组件求和为:{{ sum }}</h3><input type="text" placeholder="请输入名字" v-model="name"><button @click="add">添加</button><ul><li v-for="p in personList" :key="p.id">{{ p.name }}</li></ul></div>
</template><script>
import { name } from 'pubsub-js';
import { nanoid } from 'nanoid';export default {name:'Person',data() {return {name:''}},computed:{personList(){return this.$store.state.personList},sum(){return this.$store.state.sum}},methods:{add(){const personObj = {id:nanoid(),name:this.name}this.$store.commit('ADD_PERSON',personObj)this.name = ''}}
}
</script>

index.js

//该文件用于创建Vuex中最为核心的store
import { name } from "pubsub-js";
import Vue from "vue";
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)//准备actions——用于响应组件中的动作
const actions = {jia(context,value){context.commit('JIA',value)},jian(context,value){context.commit('JIAN',value)},jiaOdd({ commit, state }, value) {if (state.sum % 2 === 1) {commit('JIA', value);}},jiaWait({ commit }, value) {setTimeout(() => {commit('JIA', value);}, 500);},
}
//准备mutations——用于操作数据(state)
const mutations = {JIA(state,value){state.sum += value},JIAN(state,value){state.sum -= value},ADD_PERSON(state,value){console.log('mutations中的ADD_PERSON被调用了'),state.personList.unshift(value)}
}
//准备state——用于存储数据
const state = {sum:0, //当前的和school:'zzuli',subject:'Vue',personList:[{id:'001',name:'张三'}]
}//准备getters——用于将state中的数据进行加工
const getters = {bigSum(state){return state.sum*10}
}//创建并暴露store
export default new Vuex.Store({actions,mutations,state,getters,
})

vuex模块化+namespace

  1. 创建模块化的 Vuex store:将功能拆分为独立模块(count 和 person)

  2. 使用命名空间:每个模块开启 namespaced: true

  3. 组件中正确访问模块:使用带命名空间的映射方法

  4. 处理响应式问题:确保所有模板变量都已正确定义

Count.vue

methods: {//借助mapMutuions生成对应的方法,方法中会调用commit去联系mutitaions(对象写法)...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),//借助mapActions生成对应的方法,方法中会调用dispatch去联系actiosn(对象写法)...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})},computed:{//借助mapState生成计算属性,从state中读取数据。(对象写法)...mapState('countAbout',['sum','school','subject']),...mapState('personAbout',['personList']),//借助mapGetters生成计算属性,从getters中读取数据。(对象写法)...mapGetters('countAbout',['bigSum']),},

index.js

//人员管理相关配置
const personOptions = {namespaced:true,actions:{},mutations:{ADD_PERSON(state,value){console.log('mutations中的ADD_PERSON被调用了'),state.personList.unshift(value)}},state:{personList:[{id:'001',name:'张三'}]},getters:{},
}//创建并暴露store
export default new Vuex.Store({modules:{countAbout:countOptions,personAbout:personOptions}
})

路由

pages 文件放路由组件 components放一般组件

嵌套路由

  • 父路由组件:包含 <router-view> 作为子组件的容器

  • 子路由配置:在路由对象的 children 属性中定义

  • 路由出口:子内容会渲染在父组件的 <router-view> 中

  • 路径不以 / 开头:嵌套路由的路径不应添加起始 /(如 path: 'posts' 正确,path: '/posts' 错误)

  • 组件复用:当仅参数变化时,使用 onBeforeRouteUpdate 监听变化

  • 布局组合:可与命名视图结合实现复杂布局

// 该文件专门用于创建整个应用的路由器
import About from '@/pages/About.vue'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import Message from '@/pages/Message.vue'
import VueRouter from 'vue-router'
import Detail from '@/pages/Detail.vue'
//引入组件//创建并暴露一个路由器
export default new VueRouter({routes:[{path:'/about',component:About},{path:'/home',component:Home,children:[{path:'news',component:News,},{path:'message',component:Message,children:[{path:'detail',component:Detail,}]}]}]
})

路由传参

<!-- 字符串形式(不推荐) -->
<router-link to="/detail?id=123&title=消息标题">详情</router-link><!-- 对象形式(推荐) -->
<router-link :to="{path: '/detail',query: {id: 123,title: '消息标题'}
}">详情</router-link>

获取query参数

export default {mounted() {console.log('ID:', this.$route.query.id);console.log('Title:', this.$route.query.title);}
}

例子

<template><div><ul><li v-for="m in messageList" :key="m.id"><!-- 跳转路由并携带query参数,to的字符串写法 --><!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{ m.title }}</router-link>&nbsp;&nbsp; --><!-- 跳转路由并携带query参数,to的对象写法 --><router-link :to="{path:'/home/message/detail',query:{id:m.id,title:m.title}}">{{ m.title }}</router-link></li></ul><hr><router-view></router-view></div>
</template><script>export default {name:'Message',data(){return {messageList:[{id:'001',title:'消息001'},{id:'002',title:'消息002'},{id:'003',title:'消息003'},]}}}
</script>

命名路由

核心用法

1. 路由配置中定义命名路由

// router.js
import { createRouter, createWebHistory } from 'vue-router'const routes = [{path: '/',name: 'Home', // 命名路由component: HomeView},{path: '/about',name: 'About',component: AboutView},{path: '/user/:id',name: 'UserProfile', // 带参数命名路由component: UserProfile,props: true // 启用props接收参数}
]const router = createRouter({history: createWebHistory(),routes
})export default router

2. 在组件中使用命名路由

在模板中
<router-link :to="{ name: 'Home' }">首页</router-link>
<router-link :to="{ name: 'UserProfile', params: { id: 123 } }">用户资料
</router-link>

路由的params参数

与 query 参数的对比

区别点paramsquery
URL 位置路径中 (/user/123)? 后 (/user?id=123)
命名路由要求必需可选
参数保留刷新后消失(需配合历史状态管理)刷新后保留在 URL 中
使用场景资源标识(如用户 ID)可选过滤条件(如排序、分页)
  1. 定义方式

    // 路由配置中声明动态参数 (冒号开头)
    const routes = [{ path: '/user/:id', component: User },         // 路径参数{ name: 'profile', path: '/user/:id/profile' }  // 命名路由参数
    ]
  2. 传递方式

    // 编程式导航
    router.push({ name: 'profile',       // 必须用命名路由params: { id: 123 }    // 参数对象
    })// 或声明式导航
    <router-link :to="{ name: 'profile', params: { id: 123 }}">
  3. 获取参数(在目标组件内):

    // 通过 $route 对象获取
    this.$route.params.id  // 输出 123

路由的props参数

props 参数允许你将路由参数直接作为组件的 props 传递,而不是在组件内部通过 $route.params 或 $route.query 访问。

children:[{path:'news',component:News,},{path:'message',component:Message,children:[{name:'xiangqing',path:'detail/:id/:title',component:Detail,//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件// props:{a:1,b:'hello'}//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件// props:true//props的第三种写法,值为函数props($route){return {id:$route.query.id,title:$route.query.title}}}]}]
<template><ul><li>消息编号:{{id}}</li><li>消息标题:{{title}}</li></ul>
</template><script>export default {name:'Detail',props:['id','title'],mounted() {console.log(this.$route)}}
</script>

<router-link>的place属性

编程式路由导航

缓存路由组件

两个新的生命周期钩子

        activated() {console.log('News组件即将被激活了')this.timer = setInterval(() => {this.opacity -=0.01if(this.opacity <= 0) this.opacity = 1},16)},deactivated() {console.log('News组件失活了')clearInterval(this.timer)}

路由守卫

用于在路由跳转前后执行逻辑。根据执行时机,可分为前置守卫(在路由跳转前执行)和后置守卫(在路由跳转后执行)

全局守卫

  • beforeEach:检查用户是否登录,保护需要认证的路由

  • afterEach:记录导航完成日志并更新页面标题

//全局前置路由守卫——初始化的时候被调用、每次切换的时候被调用
router.beforeEach((to,from,next)=>{console.log('前置路由守卫',to,from)// if(to.path === '/home/news' || to.path === '/home/message'){if(to.meta.isAuth){  //判断是否需要鉴权if(localStorage.getItem('school') === 'mengg'){document.title = to.meta.title || '俺的系统'next()}else{alert('学校名字不对,无权限查看!')}}else{next()}
})//全局后置路由守卫——初始化的时候被调用、每次切换的时候被调用
router.afterEach((to,from)=>{console.log('后置路由守卫',to,from)document.title = to.meta.title || '俺的系统'
})

独享路由守卫

某一路由单独使用的守卫。

  • 在 /admin 路由上使用 beforeEnter 守卫

  • 检查用户是否具有管理员权限

  • 无权限用户会被重定向到首页

  • 在日志中清晰展示守卫执行过程

{name:'xinwen',path:'news',component:News,meta:{isAuth:true,title:'新闻'},//独享路由守卫beforeEnter: (to,from, next) =>{console.log('前置路由守卫',to,from)if(to.meta.isAuth){if(localStorage.getItem('school') === 'mengg'){next()}else{alert('学校名字不对,无权限查看!')}}else{next()}}},

组件内守卫

  • 在编辑页面使用 beforeRouteLeave 守卫

  • 检测未保存的更改并提示用户确认

  • 防止用户意外离开导致数据丢失

//通过路由规则,(通过点击)进入该组件时被调用beforeRouteEnter(to, from, next) {console.log('About---beforeRouteEnter',to,from)if(to.meta.isAuth){if(localStorage.getItem('school') === 'mengg'){next()}else{alert('学校名字不对,无权限查看!')}}else{next()}},//通过路由规则,离开该组件时被调用beforeRouteLeave(to,from,next) {console.log('About---beforeRouteLeave',to,from)next()}

使用说明

  1. 在首页登录(任意用户名和密码)

  2. 尝试访问不同页面:

    • 个人资料:需要登录(全局守卫保护)

    • 管理面板:需要管理员权限(独享守卫保护)

    • 编辑页面:尝试修改内容后离开(组件内守卫)

  3. 查看页面底部的守卫执行日志

  4. 使用导航菜单在不同页面间切换

Vue UI 组件库

注意

1、出现以下报错说明文件目录不对

找到pasckage.json所在目录,

cd 'D:\school project homework\Project\Vue\vue_test'

切换到所在目录后重新启动即可

2、运行失败时,此时把launch.json文件删掉,然后把刚刚打开的启动调试的页面关掉,在visual studio 中选择运行---->启动调试。

http://www.dtcms.com/a/357031.html

相关文章:

  • 二手车估值查询-二手车估值api接口
  • el-table实现双击编辑-el-select选择框+输入框限制非负两位小数
  • HunyuanVideo-Foley视频音效生成模型介绍与部署
  • 非标设计 机架模板 misumi 设计组合案例
  • 浏览器自动化工具怎么选?MCP 控制浏览器 vs Selenium 深度对比
  • 预测模型及超参数:3.集成学习:[1]LightGBM
  • LangChain实战(三):深入理解Model I/O - Prompts模板
  • 顶会顶刊图像分类的云服务器训练方法
  • 闭包与内存泄漏:深度解析与应对策略
  • Spring boot 启用第二数据源
  • Java全栈工程师的实战面试:从基础到微服务架构
  • 【SOD】目标检测
  • 2025.8.29机械臂实战项目
  • 基于STM32单片机的智能温室控制声光报警系统设计
  • leetcode 461 汉明距离
  • 基于MSRDCN、FEAM与AMSFM的轴承故障诊断MATLAB实现
  • 【工具】开源大屏设计器 自用整理
  • golang接口详细解释
  • websocket的应用
  • 【Spring Cloud Alibaba】前置知识
  • 微信小程序调用蓝牙打印机教程(TSPL命令)
  • Android 14 PMS源码分析
  • Linux-搭建DNS服务器
  • 计算机三级嵌入式填空题——真题库(24)原题附答案速记
  • CMake xcode编译器属性设置技巧
  • JavaScript 数组核心操作实战:最值获取与排序实现(从基础到优化)
  • 线程安全及死锁问题
  • Linux之Docker虚拟化技术(二)
  • Python结构化模式匹配:解析器的革命性升级
  • 大模型 “轻量化” 之战:从千亿参数到端侧部署,AI 如何走进消费电子?