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

商城版网站制作做网站的实训报告

商城版网站制作,做网站的实训报告,广州专业做网站建设,wordpress 前台刷新14.vue-router 3.x 路由安装的时候不是必须的#xff0c;可以等到使用的时候再装#xff0c;如果之前没有安装的话#xff0c;可以再单独安装。之前的终端命令行不要关闭#xff0c;再重新开一个#xff0c;还需要再package.json文件的依赖中添加。 如果忘记之前是否有安…14.vue-router 3.x 路由安装的时候不是必须的可以等到使用的时候再装如果之前没有安装的话可以再单独安装。之前的终端命令行不要关闭再重新开一个还需要再package.json文件的依赖中添加。 如果忘记之前是否有安装过可以在package.json文件中查看依赖是否有router。 vue是单页面应用(SPA在一个页面中切换)。 路由简单来说就是路径跟视图的对应关系一个路径对应一个视图。vue中的切换都是基于路由去切换的。 安装 npm install vue-router //安装指定版本 npm install vue-router3.2.0npm i jquery --save(缩写-S)生产依赖 --save-dev(缩写-D)开发依赖 将jquery安装并保存到生产依赖或开发依赖中 而现在不用这么麻烦了直接npm install jquery 直接自动保存到生产依赖中如果需要保存到开发依赖中还是需要像之前一样卸载npm uninstall jquery使用步骤 在使用组件名之前都需要引入组件所在的文件。 在 router 文件夹下的 index.js 文件中 1.引入vue、 vue-router import Vue from vue import VueRouter from vue-router 2.注册组件VueRouterVue.use(VueRouter) 因为这是为vue量身打造的只要不是vue的核心并且是为vue量身定做的才可以注册。如vue-router和vuex 3.定义路由配置项(哪个路径对应哪个视图)。------重点。①路由的核心就是路径与视图的对应关系使用路由懒加载的方式引入。②路由代表的不是整个页面而是需要变动的某一块页面需要在最大的组件App.vue中给路由视图留出位置。router-view/router-view。 //在router文件下的index.js文件中使用组件名之前是要引入组件 import MyHome from ../views/MyHome import MyAbout from ../views/MyAbout//定义路由配置项路径和组件视图 const routes[{path:/,component:MyHome},{path:/about,component:MyAbout} ]!-- 在App.vue文件中合适的位置留出路由视图的位置 -- router-view/router-view component: 组件名 在文件顶部引入组件文件 4.创建 VueRouter 实例并导出然后 在main.js的根组件中导入传入配置项挂载到实例上。 实战中使用路由的步骤(只是需要自己修改的部分每个路由文件都需要的步骤不包括如果是面试题还是上面的步骤) 1、在路由文件夹下的index.js文件下引入需要的组件文件 或者一开始不引入使用懒加载建议采用该方法 2、定义路由配置项路径和视图的对应关系。 3、在App.vue文件中留出合适的路由视图渲染的位置。router-view/router-view const routes[ {path:/,component:组件名1//使用懒加载的方法//component:()import(路径) }, {path:/about,component:组件名2 },.... ]//使用案例router文件夹下的index.js文件 import Vue from vue //引入vue import VueRouter from vue-router //引入vue-router //import MyHome from ../views/MyHome //1 引入组件或使用路由懒加载 //import MyAbout from ../views/MyAboutVue.use(VueRouter)//注册组件给vue定制的只要不是vue本身的东西使用的时候都得注册//2 定义路由配置项路径和视图的对应关系 const routes [{path: /, //默认路径开始显示的页面// component: MyHome //组件名前提是引入组件//使用路由懒加载component:()import(../views/MyHome.vue)},{path: /about,//路径不可重复以 / 开头//component:MyAbout//使用路由懒加载component:()import(../views/MyAbout)} ]//创建一个路由实例导出去在根组件main.js中引入根配置项中才能使用路由 const router new VueRouter({routes }) export default router!-- app.vue文件 -- templatedivh1{{msg}}/h1my-info/my-info router-view/router-view !-- 3 路由视图就渲染在此--/div/templatescriptimport MyInfo from ./views/MyInfo.vue //引入的组件 export default {data(){return {msg:我是App根组件}},components:{MyInfo}} /scriptstyle scopedh1{color: blue;} /style 路由的两个核心 1定义路由配置项 2定义路由视图的显示位置(router-view) 路径定义规则路径以斜线打头 页面与路由一定是一一对应的一个页面一定要对应路由否则找不到 **路由的懒加载**之前是先把组件导入不管用不用都把组件加载了那些可能用不上的组件就会发生性能浪费。使用路由的懒加载的话就先不加载组件等访问哪个页面再去加载哪个页面对应的路由。 component: () import(../views/About.vue) //只有访问该页面时才会调用该函数加载关于路径的写法 import Abc from ./demo 1.如果当前目录下有demo文件夹那么是去引入的demo文件夹下的index.js 2.如果不存在demo文件夹会优先去找当前目录下的demo.vue文件 3.如果不存在.vue文件那么会优先查找当前目录下的demo.js文件 路径中代表的是src目录本质上是因为webpack内部配置的 嵌套路由 在整个项目系统中一进来就已经分了两个一级路由了登陆注册页面和主页面如果是没有登录注册就显示登录注册页面如果登陆过了就显示主页面这两个页面中显示一个。 二级路由是点击两边的导航而切换的页面。 注意点每一级路由都必须要有该级路由的router-view。 1.哪个组件还有子路由那么需要在该组件内部定义router-view代表该组件的子路由显示在该位置上 2.子路由的配置定义在父路由的children属性下配置内容同父路由 子路由如果不加斜线那么默认在上级路由上叠加如果加了斜线那么前面必须带上 上级路由。 //配置路由项 const routes[{path:/home,name:Home,//name属性叫什么都可以但是不能重名在路由跳转的时候会用到component:()import(/views/MyHome),children:[{path:/home/about,name:About,component:()import(/views/MyAbout)}]},{path:/login,name:Login,component:()import(views/MyLogin)} ]//2 在父组件MyHome中找到路由试图router-view的位置。路由的跳转 需要路由配置项的name属性 1.js形式的跳转当用户请求成功/事件时的自动跳转 如果看到了某个方法是以$打头的基本可以断定该方法是Vue根实例的方法。 this.$router.push(字符串路径 /home/about ) //this指向的是当前组件 this.$router.push({ path: /home/about }) this.$router.push({ name: About})2.标签形式的跳转当用户点击时的跳转情况类似html中的a标签 router-link to/home/about跳转 /router-link // 1.to 可以是字符串路径 还可以是对象(但需要是js的执行环境加:) 2.:to{path:路径} 3.{name:名字} //路由嵌套少的话使用路径较好但是如果是嵌套情况较多的话建议是使用name跳转3.浏览器的跳转前提是浏览器要有记录 // 在浏览器记录中前进一步等同于 history.forward() this.$router.go(1)// 后退一步记录等同于 history.back() this.$router.go(-1)// 前进 3 步记录 this.$router.go(3)// 如果 history 记录不够用那就默默地失败呗 this.$router.go(-100) this.$router.go(100)动态路由 多个路由匹配同一个页面动态不写死。例如教务系统中查询成绩时的 www.qinghua. search / 20220101和www. qinghua. search/20220102前半部分一样都是查询页面。 使用场景多个不同的路径匹配同样的页面。也能够实现跨组件传递数据拿到动态路径的名字id但是这样的话就会出现必须传值的情况。 动态路由匹配 在路径后面加/:名字。这样在输入路径的时候名字可以是任意的他们都对应的是同一个页面。 如果想要拿到地址的名字内容在另一个页面中使用的话使用$route.params.名字(至于前面加不加this如果是在html中写的则不加如果是在js的methods中写的则要加)即可。 【this.$router拿到的是根路由实例this.$route拿到的是当前路由实例。】 如 { path: /users/:id, component: User },//可以同时存在多个动态路由 { path: /users/:id/:no, component: User },注意只改后面动态路径参数是不会重新触发组件生命周期的。 但是如果页面中用到了动态路由的数据那么切换动态路径的时候是会触发组件更新的生命周期beforeUpdate和updated的(视图需要重新渲染)。 当有动态路径发生改变想要在动态路径改变时做事情组件生命周期是不会发生变化的(只有页面中用到了动态路由的数据时才会发生变化这样就很不稳定)但是使用导航守卫中的组件内的守卫钩子beforeRouterUpdaete是能够检测到的然后在里面写我们需要做的事情就行了。 动态路由的跳转 1.this.$router.push({ name: user, params: { userId: 123 }}) //使用这种方法很方便动态路径可以将params的值设置为变量 2.this.$router.push({ path: /user/123 })//如果用这个的话还不如用下面的那个 2.this.$router.push( /user/123) //下面的写法是错误的path和parmas不能一起写一起写会导致不知道哪一个是动态路径了 router.push({ path: /user, params: { userId: 123 }})//如果提供了 pathparams 会被忽略同样的规则适用于router-link标签 查询参数 不需要使用动态路径的。 使用场景用于跨组件传递数据。(实现页面跳转并且把数据带过去在另一个页面中使用) 查询参数的跳转的时候直接在地址后面拼接?keyvalue不用像动态路由那样修改路由配置项。 router.push({ path: /register, query: { plan: private }}) router.push({ path: /register?keyvalue}}) router.push(/register?keyvaluekey2value2)接收数据的页面使用该数据时this.$route.query.key。 注意 name和params配套 path和query 配套(因为路径后面没有冲突直接就是数据)动态路由和查询参数的相同点都能实现跨页面传递数据 不同点 1.跳转方式动态路由 name params查询参数 path query. 2.动态路由更多的用于多个路径匹配同一个页面中查询参数更多用于跨组件传递数据。 而且使用查询参数不需要在路由中定义东西的不需要改路由配置项而动态路由需要先改路由表/:id。 3.动态路由传递参数不方便不管用不用都必须传值。 注意query查询参数传递的数据不要是引用数据类型的数据只能传基本类型的数据如果非要想传对象可以将其转为字符串类型的数据。 捕获所有路由 访问的路由不存在匹配不上时显示的是404页面时使用。 {// 会匹配所有路径path: *, component:()import(/views/NotFound) } {// 会匹配以 /user- 开头的任意路径path: /user-* }当使用通配符路由时请确保路由的顺序是正确的也就是说含有通配符的路由应该放在最后。 新版本不限制 通配符的存放位置也就是说就算是放在最开始其他路由也是能匹配上的不过不推荐 组件路由对象 在组件中通过this.$route拿到当前组件的路由信息 {name:组件的名字,fullPath:完整路径,path:路径,matched[匹配上的所有路由一级路由匹配上的是一个嵌套路由匹配上的是多个],meta:路由元信息params:动态路径参数,query:查询参数}重定向和别名 重定向“重定向”的意思是当用户访问 /a时URL 将会被替换成 /b然后匹配路由为 /b。 在路由配置项中添加redirect:要跳转的路径. const routes [{path:/home,name:Home,redirect:/login, //重定向加了这个一进入home页面就会自动跳转到login页面URL发生了改变alias:/abc, //别名URL没有发生改变通过这两个名字都能访问到 使用的时候很少component:()import (/views/MyHome),children:[{path:about,name:About,component:()import(/views/MyAbout)}]}, ]重定向使用场景如淘宝在未登录时购买物品一直会跳转 到登录页面。// 或者 对于管理系统而言一级路由是登录页面和主界面在进入主界面之后只显示头部和侧导航栏中间的内容是不显示的这时如果使用重定向在进入主界面之后就自动显示二级路由的一部分内容。 // 或者 输入网址后但进入的网站的网址是另一个的情况网址有风险的情况。 重定向的目标也可以是一个命名的路由 const router new VueRouter({routes: [{ path: /a, redirect: { name: foo }}] })别名/a 的别名是 /b意味着当用户访问 /b 时URL 会保持为 /b但是路由匹配则为 /a就像用户访问 /a 一样. 使用的时候很少 在路由配置项中添加alias:/abc const router new VueRouter({routes: [{ path: /a, component: A, alias: /b }] })“别名”的功能让你可以自由地将 UI 结构映射到任意的 URL而不是受限于配置的嵌套路由结构。 别名的使用场景不用按照子父级关系定义路径了之前子路由的路径得在父路由路径的基础上添加使用别名后可以直接写子路由的路径不用再受父级路径的影响了但是新版本修改后 不用别名就已经支持了。 路由组件传参(针对动态路由而言的) 可以将params直接映射到组件的属性中。 步骤将路由组件中的路由配置项的属性props设置为true这样动态路径就会作为参数传入到组件中然后在组件中接收一下就可以直接用 。 使用动态路由this.$route.params.id之前的做法能拿但是很麻烦 const User {template: divUser {{ $route.params.id }}/div//2 在组件中要拿到id }const router new VueRouter({routes: [{ path: /user/:id, component: User }]//1 动态路由/:id })用了组件传参后 const User {props: [id,num],//2 在相应的组件中的js中(不是放在data中与data同级)接收一下传过来的props后可直接使用template: divUser {{ id }} {{ num }}/div } const router new VueRouter({routes: [{ path: /user/:id/:num, component: User, props: true },//1 将路由组件中路由配置项的属性props设置为true这样动态路径就会作为属性参数传入到组件中然后在组件中接收一下就可以直接用 ] }) props的来源现在props可能是父-子传值中父组件传过来的也有可能是路由中带的。 路由模式 默认的路由模式是hash模式在创建项目的时候有问是否选择history模式我们当时选择的是N。 hash模式的特点URL地址栏是拼接在#后面的#是一定会在的即使是删掉也会在。hash模式丑实际中都不使用。 改路由模式的方法在路由文件创建路由对象时添加一个mode属性 const routernew VueRouter({routes,mode:history //将路由模式改为history模式 })hash模式和history模式 面试题history模式使用时存在的最大问题是会导致刷新404的问题。 原因hash模式是基于hash值来做的#后面的hash值是不会发往后台的那是前端自己定义的路由自己用的发送请求查找服务器时是会忽略掉#后面的内容的是按照#前面的内容查找的是能成功查找到的而history模式是按照完整的路径地址查找的刷新时会按照完整的路径去后台服务器中查找但是由于这个地址时前端定义的在服务器是没有这个路径的是无法在后台找到的就会发生找不到页面404。如hash模式的http://localhost:8080/#/home在向服务器发送请求时发送的地址只是#前面的http://localhost:8080/是能够成功找到的而history模式发送请求时使用的是完整的地址http://localhost:8080/home该地址在服务器中是找不到的出现404。要解决这个问题就需要后端配置nginx反向代理做重定向当请求的路径不存在时重定向到首页。 当你使用 history 模式时URL 就像正常的 url例如 http://yoursite.com/user/id也好看 不过这种模式要玩好还需要后台配置支持。因为我们的应用是个单页客户端应用如果后台没有正确的配置当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404这就不好看了。 要解决这种问题就需要后端做一个nginx做一个反向代理做重定向如果请求的路径不存在重定向到首页。----这个问题是由后端配置的 所以呢你要在服务端增加一个覆盖所有情况的候选资源如果 URL 匹配不到任何静态资源则应该返回同一个 index.html 页面这个页面就是你 app 依赖的页面。 如果面试官继续往下问是怎么做重定向的那就回答是由后端做nginx代理做的不是前端做的。 导航守卫/路由守卫 限制哪些能跳转哪些不能跳转。 使用场景如淘宝中未登录就支付是不可以的有路由守卫拦下来。/ 或者权限管控。 全局前置守卫 全局访问项目中的任何一个路由都会拦下来前置在还没跳转之前就拦下来。 使用场景一般用来做整个项目的管控如未登录时要求要先去登录。 beforeEach不用主动去调用当有组件之间的跳转时就会自动的触发。 //在router文件夹下的index.js文件中创建的路由实例 const router new VueRouter({ ... })//beforeEach方法是我们创建的路由实例router的方法 router.beforeEach((to, from, next) {//根据判断条件能否进入到下一个页面 })to: Route: 即将要进入的目标 路由对象 (路由对象就是this.$route拿到当前组件的路由信息)from: Route: 当前导航正要离开的路由next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。—next方法需要主动调用。下面第一种和第三种是用的最多的。 next(): 进行管道中的下一个钩子。如果全部钩子执行完了则导航的状态就是 confirmed (确认的)。主动调用next()表示放行直接往下进入下一个组件。----------------使用较多的next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮)那么 URL 地址会重置到 from 路由对应的地址。从哪来回哪去。next(/)** 或者 **next({ path: / }): 跳转到一个不同的地址。当前的导航被中断然后进行一个新的导航。你可以向 next 传递任意位置对象且允许设置诸如 replace: true、name: home 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。强制去另一个路径。(如淘宝种未登录去支付被强制转换到登录页面)------------------使用较多的next(error): (2.4.0) 如果传入 next 的参数是一个 Error 实例则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。 注意避免死循环下面的写法是死循环 let flag false;//存储的是登录的状态 //全局前置守卫 router.beforeEach((to, from, next) {if(flag){next();//直接放行}else{next(/login) 跳转到登录页面。在未登录状态时会发生死循环} })先看是否登录未登录要去登录页面而想要去登录页面又要检查是否登录一看未登录就要去登录页面而主只要想去其他页面就要进行检查这样就陷入了死循环。 解决方法在状态是未登录需要转向登陆页面时做一个判断判断当前是否是要去登录页面如果是的话放行否则还是得要去登陆页面。加个验证就ok了。 let flag false;//存储的是登录的状态 //全局前置守卫 router.beforeEach((to, from, next) {if (flag) {next();//直接放行} else {//在是未登录状态需要转向登录页面时加一个验证如果是要去登录页面的就让他过去否则如果是要去其他页面的话不让过还是需要去登陆页面if (to.path /login) {next()} else {next(/login);//跳转到登录页面}} })全局解析守卫(用的很少) 在 2.5.0 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似区别是在导航被确认之前同时在所有组件内守卫和异步路由组件被解析之后解析守卫就被调用。 全局前置守卫和全局解析守卫只是守卫的时机不同。全局前置守卫是在进大门的时候检查而全局解析守卫是在进入大门之后再进入每一个小门的时候检查。 全局后置钩子 钩子在特定的情况下会自动运行的函数。 跳转到某个页面之后需要做事情一般可以用组件的生命周期来写。全局后置钩子与组件自己的生命周期类似一般就不用了。 //和守卫不同的是这些钩子不会接受 next 函数也不会改变导航本身 router.afterEach((to, from) {// ... })路由独享的守卫 不需要给全局加守卫只给其中某些重要的页面加守卫。beforeEnter:(to,from,next){} //在路由配置项中写的 const router new VueRouter({routes: [{path: /foo,component: Foo,beforeEnter: (to, from, next) {// ...}}] })组件内的守卫 在对应的组件.vue中写。 export default {mounted(){console.log(this.$route)},beforeRouteEnter(to, from, next) {// 在渲染该组件的对应路由被 confirm 前调用// 不能获取组件实例 this// 因为当守卫执行前组件实例还没被创建},beforeRouteUpdate(to, from, next) {// 在当前路由改变但是该组件被复用时调用// 举例来说对于一个带有动态参数的路径 /foo/:id在 /foo/1 和 /foo/2 之间跳转的时候// 由于会渲染同样的 Foo 组件因此组件实例会被复用。而这个钩子就会在这个情况下被调用。// 可以访问组件实例 this//使用场景当有动态路径发生改变想要在动态路径改变时做事情组件生命周期是不会发生不会的但是使用组件内的守卫是会发生变化的。},beforeRouteLeave(to, from, next) {// 导航离开该组件的对应路由时调用// 可以访问组件实例 this}}//进入该路由时执行该路由中参数改变时执行离开该路由时执行。完整的导航解析流程 全局守卫先于局部守卫的执行。 导航被触发。在失活的组件里调用 beforeRouteLeave 守卫。调用全局的 beforeEach 守卫。在重用的组件里调用 beforeRouteUpdate 守卫 (2.2)。在路由配置里调用 beforeEnter。解析异步路由组件。在被激活的组件里调用 beforeRouteEnter。调用全局的 beforeResolve 守卫 (2.5)。导航被确认。调用全局的 afterEach 钩子。触发 DOM 更新。调用 beforeRouteEnter 守卫中传给 next 的回调函数创建好的组件实例会作为回调函数的参数传入。 路由元信息 定义路由的时候可以配置 meta 字段。通过this.$route拿到meta信息。 const routes [{path: /home,name: Home,meta:{a:123},//meta路由元信息component: () import(/views/MyHome),children: [{path: about,name: About,alias: /abc,meta:{auth:boss},//meta路由元信息权限判断当前组件的meta是否是bosscomponent: () import(/views/MyAbout),}]}, ]使用场景meta可以设置一些跟当前路由相关的自定义信息比如页面标题面包屑导航页面权限等。 滚动行为 由于页面内容较多出现了滚动条上面的内容不是我们想要看的下面才是我们想要跳转页面过来后直接定位到想要看的部分不想手动向下滑动。 有滚动条的前提下才生效没有滚动条不生效 在路由实例中加 const router new VueRouter({routes,//更改路由模式mode: history,//滚动行为scrollBehavior(to, from) {//to from是路由对象 我们不想所有的页面都滚动到相同的位置to用于判断去到的是a页面滚到这里如果去到的是b页面滚动到那里console.log(to, from)// return 期望滚动到哪个的位置 x是离左边距离 y是离顶部距离//有滚动条的前提下才生效没有滚动条不生效return { x: 0, y: 1000 }} })vue-router总结 //router文件夹下的index.js文件 import Vue from vue //引入vue import VueRouter from vue-router //引入vue-routerVue.use(VueRouter)//注册组件给vue定制的只要不是vue本身的东西使用的时候都得注册//路由配置项 const routes [{path: /home,name: Home,//路由跳转的时候会用到redirect: /home/about,//重定向alias: /b,//别名meta:{auth:boss},//路由元信息像页面标题、面包屑导航、页面权限component: () import(/views/MyHome), //路由懒加载的方式引入beforeEnter: (to, from, next) {// ...console.log(to,from,next)},//路由独享的守卫children: [{path: about,name: About,component: () import(/views/MyAbout),//children:[]//还需要在MyHome父组件中写出router-view/router-view的位置}]},{//动态路由的内容path: /login/:id,//动态路由 如果想要在组件中拿到id的内容1.this.$route.params.id 2.使用路由组件传参:在路由配置项的对应路由中加属性pross:true然后再对应组件.vue的js中接受一下props:[id,no]这样就可以直接使用id和no了name: Login,component: () import(/views/MyLogin),//props:true},{//捕获所有路由 404的处理path: *,component: () import(/views/NotFound)} ]//创建路由实例导出到main.js const router new VueRouter({routes,mode: history,//更改路由模式//滚动行为scrollBehavior(to, from) {//to from是路由对象 我们不想所有的页面都滚动到相同的位置to用于判断去到的是a页面滚到这里如果去到的是b页面滚动到那里console.log(to, from)// return 期望滚动到哪个的位置 x是离左边距离 y是离顶部距离//有滚动条的前提下才生效没有滚动条不生效return { x: 0, y: 1000 }} })// 全局前置守卫 let flag false;//存储的是登录的状态 router.beforeEach((to, from, next) {if (flag) {next()// console.log(from)} else {//注意发生死循环情况的解决加一个验证就ok了if (to.path /login) {next()} else {next(/login)}} }) //全局后置钩子 /* router.afterEach((to, from) {console.log(to, from) }) */export default router关于路由跳转 1.普通路由的跳转 1.js形式的跳转this.$router.push(/login) this.$router.push({path:/login}) this.$router.push({name:Login})2.标签形式的跳转 router-link to/login 跳转 /router-link router-link :to{path:/login} 跳转 /router-linkrouter-link :to{name:Login} 跳转 /router-link 3.浏览器形式的跳转this.$router.go(1) this.$router.go(-1)2.动态路由的跳转需要修改路由配置项 /:id/:no name—parmas 1.js形式的跳转this.$router.push(/login/123/456) this.$router.push({path:/login/123/456}) this.$router.push({name:Loginparams:{id:123,no:456}})2.标签形式的跳转与js形式类似 3.查询参数的跳转 不需要修改路由配置项 path—query 1.js形式的跳转this.$router.push(/login?keyvaluekey2vlaue2) this.$router.push({path:/login?keyvaluekey2vlaue2}) this.$router.push({path:/login,query:{key:value,key2:value2}})2.标签形式的跳转与js形式类似 面试题实现跨页面的数据传递的方法有哪些 动态路由:parmas this.$route.params.名字查询参数:query;(更建议使用的) this.$route.query.名字本地存储在一个页面存储数据在另一个页面取数据没有产生跨域。(如果使用的话建议使用sessionStorage这样页面关闭之后数据就会消失不会产生日积月累使用导致存满的情况) sessionStorage.setItem()和sessionStorage.getItem().路由组件传参实际上还是动态路由的方法只是接收取数据的方式不一样。将路由组件中的路由配置项的属性props设置为true这样动态路径就会作为参数传入到组件中然后在组件中的props(与data同级)接收一下就可以直接用 。 15.Axios 前后端交互使用ajax但是原生的ajax很复杂麻烦不想用后来有了jquery的ajax简单了许多在vue中也可以使用jquery的ajax但是jquery的 包很大而且jq的ajax有回调地狱的问题(后来使用promise来解决异步的问题)因此基于这些在vue中就不适用jq的ajax了而是使用axios。 axios并不是vue中的内容也不是vue独有的react也可以使用. 安装 Axios是一个基于Promise封装的一个http库可以用于浏览器和node.js中Axios是通过promise实现对ajax技术的一种封装就像jQuery实现ajax封装一样 安装npm install axios. 使用 1.引入import axios from axios。(想在那个页面中使用就在哪个页面中引入即可不是所有的页面都需要发请求的。) 但在实际项目中许多页面都需要发送请求我们不想要每次用都要引入axios可以将引入axios放在main.js文件中的根实例上但是axios不是Vue的配置项不能route一样写在里面我们可以将axios挂载在Vue的原型上这样创建的每一个Vue实例都可以使用axios了。----------使用时this.$axios({}) import axios from axios Vue.prototype.$axiosaxios;//加$是为了区分是根实例的方法【不需要像VueRouter一样注册axios不仅在vue中使用在react中也是可以使用的。】 2.发送get/post请求。 axios请求返回的结果是一个Promise对象并将请求成功的数据直接resolve出来。如果请求失败写在then的第二个参数中。 请求返回的结果拿到的数据就是JSON格式不需要再转成JSON。 想要一进来就发请求可以将请求写在生命周期creacted中。 发送get请求 axios({method: get, // (默认是get请求)url: /user/12345,params: {//请求参数firstName: Fred,lastName: Flintstone} }) .then((res){//res就是请求成功返回的结果},(err){//err就是请求失败返回的结果});快捷发送get请求 //axios.get(url,{params:{}}) axios.get(/user/12345,{params:{firstName: Fred,lastName: Flintstone } }).then((res){//res是请求返回的数据 })发送post请求 axios({method:post,url:/user/12345,data:{firstName: Fred,lastName: Flintstone} }).then((res){//res就是请求成功返回的数据})快捷发送post请求 //axios.get(url,{}) axios.get(/user/12345,{firstName: Fred,lastName: Flintstone }).then((res){//res是请求返回的数据 })注意使用get请求和post请求时的请求方式中method不加s。(注意与单文件组件中的函数方法methds相区分) get请求和post请求不同的地方 1.method由get变为post 2.传送的数据由params变为data. 3.快捷发送请求中发送请求参数时get请求是个对象 {params:{key1:value1}}而post请求不用data直接写参数 {key1:value1}. axios请求案例 高德地图开放平台的天气查询 templatedivh1我是axios组件/h1/div/templatescriptimport axios from axiosexport default {created(){axios({method:get,url:https://restapi.amap.com/v3/weather/weatherInfo,params:{key:e17d487bab9ea0753d34762321979db4,city:南宫}}).then((res){//res就是返回来的数据console.log(res)})}} /scriptstyle scoped/style 自定义axios实例 不用上面现成的axios自己创建一个. axios.create({})返回的是一个axios实例以后就发送请求都用这个在所有页面中通用不用发送一个请求创建一个。将自定义axios实例的方法单独放在一个文件夹中。 axios.create({//配置项 })关于配置项 以下配置中只有url是必须的如果没有配置method将默认使用get方法。 url和method每个页面都是不一样的在封装axios的时候不将其放进去。 url: ‘/user’ 用户请求服务器资源的 URLmethod: ‘post’ 创建请求时使用的方法baseURL: http://demo-domain:8080/api/** 自动加在URL(非绝对路径时)前的路径所有的请求在发送的时候会自动添加该前缀。**headers: { ‘x-Requested-With’: ‘XMLHttpRequest’} 自定义请求头params: { ‘ID’: ‘12345’ } 与请求一起发送的URL参数当method指定为GET时使用data: { ‘name’: ‘zhangfs’ } 请求主体参数用于PUTPOSTPATCH方法timeout: 8000 请求超时时间0表示无超时超过时间请求被中断withCredentials: false //表示跨域请求时是否需要使用凭证,是true的时候开启withCredentials后服务器才能拿到你的cookie当然后端服务器也要设置允许你获取你开启了才有用。 拦截器 请求拦截器 axios.interceptors.request 请求拦截器在数据请求之前有一个函数给拦下来。只要发任何请求就会执行。 希望每次请求之前做什么事在请求发送之前需要验证一些信息。例如在每次请求之前需要先拦下来看看是否登录了。 与导航守卫相似导航守卫拦截的是导航跳转的情况 拦截器拦截的是发送请求的情况。 拦截器是全局的加了拦截器之后只要发送请求都会拦下来做验证。 // 注意这里面有 2 个函数——分别是成功和失败时的回调函数 axios.interceptors.request.use(function(config) {// 发起请求前执行一些处理任务return config; // 返回配置信息 }, function (error) {// 请求错误时的处理return Promise.reject(error); });config是一个对象就是请求的时候的一些配置信息可以在拦截器中更改一些参数像请求头、请求参数等。必须返回config配置信息这个请求才能发出去。 响应拦截器 axios.interceptors.response 响应拦截器数据回来之前有一个函数给拦下来。 例如天气查询时返回的数据先要判断是否存在再做后续的操作这时可以使用响应拦截器。 axios.interceptors.response.use(function(response) {// 处理响应数据return response; // 返回响应数据 }, function (error) {// 响应出错后所做的处理工作return Promise.reject(error); });response就是请求返回来的数据。 关于本地存储 属于js的知识但在vue的项目中使用很多在实际工作中使用的价值还是很高的。 一般情况下数据是存放在数据库中的但是在一些情况下还是需要存储在本地的如记住登录时记住密码如果密码是存在数据库中的话换一台电脑密码是会被记住的而实际上是是在当前电脑上记住了。/ 或者网站浏览的历史记录。 三种浏览器存储数据的方式localStroage、sessionStorage和cookie. 任何本地存储的数据是不能跨域访问的。 本地存储的数据在浏览器中是可以看到的在右键检查–Application/应用—左侧的Storage中有LocalStorage、SessionStorage、cookies点开之后有存储的key和value。 1.sessionStorage和localStorage sessionStorage和localStorage存储的值只能是字符串类型的如果想要存储其他类型的需要将其使用 JSON.stringfy()转为字符串。 sessionStorage只要关闭页面存储的数据就会消失localStorage的数据不删除是永久不会消失的。 //1.保存数据 sessionStorage.setItem(key,value) localStorage.setItem(key,value) //2.获取数据 sessionStorage.getItem(key) localStorage.getItem(key) //3.删除数据 sessionStorage.removeItem(key) localStorage.removeItem(key) //4.清空数据 sessionStorage.clear() localStorage.clear()2.cookie // 设置cookie document.cookie usernameorochiz document.cookie age20 // 读取cookie var msg document.cookie console.log(msg) // usernameorochiz;age20 // 添加过期时间单位天 var d new Date() // 当前时间 var days 3 // 3天 d.setDate(d.getDate() days) document.cookie usernameorochiz;expiresd // 删除cookie 给某个键值对设置过期的时间 d.setDate(d.getDate() - 1) console.log(document.cookie)cookie的创建比较麻烦在项目中cookie的操作都是基于第三方插件来实现的因为存储时只能存储字符串形式的keyvalue在取值时拿到的也是字符串类型的想要拿到key和value很麻烦还需要以“和”;切割等复杂程序。 cookie不是主动删除的是在一段时间后自己过期删除的。 3. (高频面试题)sessionStroage、LocalStorage和cookie的异同点。 存储时间有效期不同1、cookie的有效期是可以设置的默认的情况下是关闭浏览器后失效2、sessionStorage的有效期是仅保持在当前页面关闭当前会话页或者浏览器后就会失效3、localStorage的有效期是在不进行手动删除的情况下是一直有效的。sessionStroage关闭页面就失效LocalStorage不删除永久不失效cookie超过规定时间就失效。存储大小不同1、cookie的存储是4kb左右存储量较小一般页面最多存储20条左右信息2、localStorage和sessionStorage的存储容量是5Mb(官方介绍可能和浏览器有部分差异性)cookie小sessionStorage和Local Storage更大一些;与服务端的通信1、cookie会参与到与服务端的通信中一般会携带在http请求的头部中例如一些关键密匙验证等。2、localStorage和sessionStorage是单纯的前端存储不参与与服务端的通信cookie会在请求头中跟随请求一同发往服务器的。sessionStorage和Local Storage纯前端不参与服务的的通信。 vuex不是永久存储一刷新就没有了只是临时过度的。如果想要刷新浏览器不丢失数据只有存储到本地存储LocalStorage、SessionStorage、cookies或数据库中。 vue跨域请求代理配置 配置在vue.config.js文件中vue的其他配置。 每次需要改的地方只有target的内容在写代理的路径时要注意是几个页面前面共同的部分路径。 注意只要改了请求代理的配置必须重启服务(ctrlc,Y), 并且更改axios的url为’/api’ devServer: {proxy: { //配置跨域/api: {target: https://api.binstd.com/recipe, //每次需要更改的地方填写请求目标的地址//ws:true,changeOrigin: true,//允许跨域pathRewrite: {^/api: //请求的时候使用这个api就可以}}} }// devServer请求本地/开发服务器 // proxy/ˈprɒksi/ 代理 // target存放用来想请求的路径地址 // pathRewrite路径重写 // ^/api ^代表以什么开头以/api开头重写为空因为在真正发送请求的时候路径中是不存在/api的// 用 /api来代替想要请求的地址/api/search相当于https://api.binstd.com/recipe/search也可以不叫’/api’随便都行只是约定俗成而已。 15.综合案例使用vue-routeraxios实现美食项目 项目前的准备 使用现成的接口极速数据专门用来提供数据服务的。 直接使用脚手架创建项目从vue create 项目名称开始 与之前不同的地方 1.没选css预处理器 2.选择history模式 项目创建好之后需要做的步骤 删除不要的文件 1.components文件夹下的全部文件 2.views文件夹下的全部文件 3. App.vue只剩下router-view 4.router文件夹下的index.js中的引入和路由配置项全部删掉。 2.创建分析项目时需要考虑的步骤 1.先分析路由结构一级路由--登录和主页二级路由--主页中的点击导航栏中的内容。美食项目的路由结构不需要登陆只需要一个主页面、一个详情页点击菜之后进入详情页这两个页面是同级路由即两个一级路由(因为详情页不是在主页的基础上再显示子父级关系是子级在父级的基础上显示内容)没有嵌套。 将页面转换为移动端的页面右键检查页面左侧有一个标志点击之后就变为了移动端的显示方式在上方可以调节手机型号和尺寸100%。 3.安装axios. 项目实现过程 极速数据 appkey34daa84d8da46182 还能用299dbc7685b99190 urlhttps://api.jisuapi.com/recipe/ 定义完了.vue组件之后下一步就要定义路由。 一、最上面是搜索框只要使用了搜索框下一步一定是双向绑定。 1.调整搜索框的大小在移动端中不要直接给定大小要使用响应式布局。(最简单最常用的是百分比还可以是flex布局和rem布局) 2.搜索框输入内容后回车显示结果。 1回车需要按键修饰符keyup.entersearch. 2发送请求需要安装axiosnpm install axios由于不只是一个页面需要axios将引入axios的语句放在main.js文件中并将axios挂载到Vue的原型上这样创建的所有的Vue实例都能使用了(父类原型上的所有属性他的子类全部都可以使用)。(像router是vue特有的属性可以放在根实例中的配置项而axios不是vue的配置项不能直接写在根实例中)-------使用时this.$axios({}) import axios from axios Vue.prototype.$axiosaxios;//加$是为了区分是根实例的方法3发送请求从http://localhost:8080/到https://api.binstd.com/recipe/search会产生跨域问题(浏览器与服务器之间才会产生跨域)。 在vue和react中最常用的**解决跨域问题**的方法请求代理。先把浏览器将请求发送给本地服务器中(这二者之间不产生跨域)再由本地服务器发送给远程服务器(服务器与服务器之间不存在跨域)。**请求代理配置**方法在vue.config.js文件中加入以下配置将axios中的url的内容改为/api/search并重启服务器。访问/api就当对于访问[https://api.binstd.com/recipe/search了。](https://api.binstd.com/recipe/search了。)devServer: {proxy: {/api: {target: https://api.binstd.com/recipe, //每次需要更改的地方changeOrigin: true,//允许跨域pathRewrite: {^/api: //请求的时候使用这个api就可以}}} }3.在搜索框输入内容直接跳转到详情页展示内容。 搜索框回车后转到详情页在详情页发送请求由于在详情页可以通过搜索框发送的请求和点击分类发送的请求所需的接口参数不一样因此需要判断需要进行哪一个的请求我采用的方法是给搜索框跨页面传递参数query的时候加一个flag在详情页接收的时候判断是否有flag属性若有的话执行搜索框的请求若没有执行分类的请求。如果二者都传递过去flag的属性会被覆盖 二、清除浏览器自带的margin和padding不能将这些样式写在某一个文件中的style中由于scoped这样会只在该文件中起作用。 解决方法在src下新建一个文件夹common在commom文件夹下新建一个文件叫common.css将项目中共用的样式写在里面再将common.css文件引入到main.js中import ./common/common.css直接引入整个文件。 项目中共用的样式有清除margin和padding、清除浮动、类别li样式、去掉a标签的默认样式和颜色。 *{margin:0;padding:0;} li{list-style:none;} .fl{float:left;} .fr{float:right;} .clear{clear:both;} a{color:#333;text-decoration:none;}三、一进入到主页在用户自己输入之前是会有一部分内容的推荐的。在页面一创建就推荐使用生命周期created或者mounted。 1.请求的地址与前面的不同封装的请求代理的地址是几个页面共同的前半部分这一块在发送请求时的路径是 /api/class。所有请求的地址都有前缀/api这就让我们想到了自定义axios实例封装baseURL。(先不做暂时不要求规范) 2.每个发送请求都需要使用参数appkey想要使用请求拦截器。(先不做暂时不要求规范) 3.使用v-for循环创建推荐内容。 4.页面一进去下面不是空白的默认的推荐是按照功效来分的。 5.点击上面的分类推荐显示不同的分类。 四、点击下面具体的分类跳转到详情页在详情页发送查询详情的请求需要传递参数classsId. 1.注意是在主页发送请求数据返回到主页再由主页将数据带到详情页还是在详情页再发送详情页请求 一定是要在进入到详情页之后再发送请求在主页发送请求的话数据又不在主页中用还得带过去麻烦死了于是干脆直接在详情页发送请求。 2.点击分类时需要跳转到详情页并且把查询详情时所需要的参数数据传送到详情页使用参数查询实现跨页面传递数据。 3.点击分类后一进入详情页就发送请求显示详情的内容将发送请求写在生命周期函数created中。 4.在实际工作中请求返回的数据在赋值前一定要先判断是否为空就像之前天气查询返回来的数据为空的情况一般后端都会给返回一个status表示是否有数据。先不做暂时不要求规范 5.菜品名称、图片、简介、原材料、烹饪步骤 如果没有id当key可以使用name做key如果还是没有也可以使用index. 6.使用 {{}} 在内容中会出现带标签的不识别标签我们可以使用识别标签的v-html将内容渲染到页面中。 在整个项目中都会用到到不用每次用每次都引入的 1.common.css文件 2.axios挂载到Vue原型上 代码 common文件夹下的common.css *{padding: 0;margin: 0; } li{list-style: none; } .fl{float: left; } .fr{float: right; } .clear{clear: both; } a{color: #333;text-decoration: none; }roouter文件夹下的index.js import Vue from vue import VueRouter from vue-routerVue.use(VueRouter)const routes [{path: /,name: home,component: () import(/views/HomeView)},{path:/detail,name:detail,component:()import(../views/TypeDetail)}]const router new VueRouter({mode: history,routes })export default router views文件夹下的HomeView.vue templatedivinput typetext classsearch v-modelsearchValue keyup.entersearchdiv classrecommenddiv classtags v-for(item,index) in tagList :keyitem.classid clickselect(index){{item.name}}/div/divdiv classtypediv classtype-item v-foritem in typeList :keyitem.classid clicktoDetail(item.classid){{item.name}}/div/div/div/templatescript export default {data() {return {searchValue: ,tagList: [],typeList: [],};},methods: {//搜索框回车后转到详情页查询:通过传过去的是否有flag属性来判断做的是什么操作。search() {this.$router.push(/detail?keyword${this.searchValue}flagtrue);},recommend() {this.$axios({url: /api/class,method: get,params: {appkey: 34daa84d8da46182,},}).then((res) {this.tagList res.data.result;this.typeList res.data.result[0].list.slice(0, 10); //截取前10条数据//截取子数组的方法是slice});},select(index) {this.typeList this.tagList[index].list.slice(0, 10);},toDetail(classid) {this.$router.push(/detail?classid${classid});},},created() {this.recommend();}, }; /scriptstyle scoped .search {width: 90%;height: 30px;margin-left: 5%;margin-top: 10px; } .tags {display: inline-block;background-color: blanchedalmond;padding: 0 5px; /* 由于每个标签的文字多少不同不能直接给定宽度使用padding来解决 */height: 20px;text-align: center;line-height: 20px;margin-left: 5px;margin-top: 10px; } /* .wrap{width: 90%;margin-left: 5%;} */ .type-item {width: 45%;height: 100px;background-color: aqua;margin-left: 3%;display: inline-block;text-align: center;line-height: 100px;margin-top: 10px; } /style views文件夹下的TypeDetail.vue templatedivdiv v-for(item, index) in detailList :keyitem.idh1{{ index 1 }}.{{ item.name }}/h1img :srcitem.pic /div v-htmlitem.content/divh2原材料/h2ulli v-form in item.material :keym.mname{{ m.mname }}:{{ m.amount }}/li/ulh2烹饪步骤/h2ulliv-for(m, index) in item.process:keyindexv-htmlindex 1 . m.pcontent/li!-- 注意识别标签中的文本使用v-html可以对其进行拼接 --/ul/div/div/templatescript export default {data() {return {detailList: [],};},created() {if (flag in this.$route.query) {//按照输入框查询this.$axios({url: /api/search,method: get,params: {keyword: this.$route.query.keyword,num: 10,start: 0,appkey: 34daa84d8da46182,},}).then((res) {this.detailList res.data.result.list;});} else {this.$axios({url: /api/byclass,method: get,params: {classid: this.$route.query.classid, //注意这里通过查询参数传过来的数据拿去方法要记得加.classidstart: 0,num: 10,appkey: 34daa84d8da46182,},}).then((res) {this.detailList res.data.result.list;});}}, }; /scriptstyle scoped /style App.vue templatediv idapprouter-view//div/templatestyle/style main.js import Vue from vue import App from ./App.vue import router from ./router import ./common/common.css //引入样式到所有文件 import axios from axiosVue.config.productionTip false Vue.prototype.$axios axios // 将axios挂载到Vue实例的原型上new Vue({router,render: h h(App) }).$mount(#app) vue.config.js const { defineConfig } require(vue/cli-service) module.exports defineConfig({transpileDependencies: true,devServer: {proxy: { //配置跨域/api: {target: https://api.jisuapi.com/recipe/, //每次需要更改的地方填写请求目标的地址//ws:true,changeOrigin: true,//允许跨域pathRewrite: {^/api: //请求的时候使用这个api就可以}}}} }) 16.Vuex 3.x 使用vuex来进实现子-父传值、子-子传值以及更复杂的传值像父-子传值这种简单的传值就是用props即可。 注意 Vuex 3.x版本是与Vue2.0版本配套 Vuex4.x版本是与Vue3.0版本配套 概念 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库(也就是公共数据管理模式)。它采用集中式存储管理应用的所有组件的状态并以相应的规则保证状态以一种可预测的方式发生变化 这么说吧将vue想作是一个js文件、组件是函数那么vuex就是一个全局变量只是这个“全局变量”包含了一些特定的规则而已。 使用 npm install vuex注意安装的时候如果有以下报错,说明是安装版本过高导致安装低版本即可解决 解决方案: npm install vuex3.6.2再单独创建一个文件夹store在里面创建一个index.js里面的内容如下与vue-router各方面都很类似 //store文件夹下的index.js文件内容 1引入 2注册 3创建vuex实例并默认导出 4main.js引入使用 import Vue from vue import Vuex from vuex Vue.use(Vuex) //store的意思是商店组件之间的传值直接都从store中拿不管两个组件之间是什么关系 const store new Vuex.Store({state: {count: 0},mutations: {increment (state) {state.count}} }) export default store//main.js const app new Vue({el: #app,// 把 store 对象提供给 “store” 选项这可以把 store 的实例注入所有的子组件store, })五大核心概念 vuex中的state数据和getters映射到组件中的计算属性中mutations映射到组件中的methods中时尽量使用相同的名字这样便于找到。 vuex中的getters、mutations都必须要有第一个参数stateactions的第一个默认参数是context state getter 第一个默认参数是state第二个默认参数是getters mutation 第一个默认参数是state第二个参数是载荷payload action 第一个默认参数是context第二个参数是载荷payload state 状态state里存放的其实就是希望共享的数据。 const store new Vuex.Store({state: {count: 10,like:[篮球,足球],movie:{name:速度与激情,actor:保罗沃克}} })**vuex中state的数据在组件中使用的时候一般都放在计算属性computed中**这样能够在数据发生变化时驱动视图响应式发生变化。 在其他组件取出共享的数据的方法this.$store.state.count getters getters与计算属性不同的地方在使用上面的数据的时候不同computed是直接this.count而getters必须通过第一个参数state.count。 类似于计算属性不同的是在使用state里面的数据时与computed使用data里的数据this.gender不一样getters里面的要接收参数默认接受第一个参数该参数是所有的state其他的用法跟computed是一模一样的 第二个参数是所有的getters 1.基本用法 getters里面的属性不能与state里的重名。 //index.js文件中 const store new Vuex.Store({state: {count: 10},getters:{money(state){return state.count元}} })//组件中取出数据computed:{money(){return this.$store.getters.money}}在其他组件中取出getters的方法this.$store.getters.money 2.getters也可以传参(和计算属性一样返回一个函数即可) 使用场景同一个数据在不同的页面中有不同的换算结果。 //index.js文件中getters:{change(state){return (rate){return state.money*rate}}}//组件中取数据,如果在组件中使用该数据的时候还需要传参则计算属性中也需要返回一个函数来传参 computed:{change(){//注意这里计算属性中函数名不能传参得在return函数中写参数return (rate){return this.$store.getters.change(rate)}} }//组件中使用该数据 {{change(0.6)}}3.getters的第二个参数:所有getters 计算属性computed中可以使用data中的数据同时也可以使用其他的计算属性和props。同样getters中也可以除了使用state中的数据也可以使用其他的getters. getters:{info(state){return state.count*2},money(state,getters){ return getters.info元}}mutations mutations这里定义一些改state数据的方法。 之前在组件中想要更改data中的数据直接this.count新值即可而想要修改vuex中state的数据是不能直接改this.$store.state.count新值的必须要通过mutations修改。 1.修改state数据的唯一办法就是提交mutation 2.mutations中修改的数据如果是引用类型一定注意要完整的赋值不能单独修改某一项。如果觉得完整赋值很麻烦可以通过深复制将数据复制给另一个变量修改另一个变量的某一项再将另一个变量赋值给该数据即可。 修改state中的对象和数组的不同方法 1、数组法一完整替换 法二深复制.更好let narr[...arr] narr[0]w arrnarr2、对象法一完整替换 法二深复制相同属性名后面的属性值覆盖前面的属性值。更好person{...person,salary:8000}**1.基本用法 接收默认的第一个参数state ** 就是你想做的事情的列表mutation要通过commit提交. //index.js文件 const store new Vuex.Store({state: {count: 1,person:{name:小明,age:25,salary:5000},arr:[h,e,l,l,o],},mutations: {addCount (state) {// 变更状态state.count},changePerson(state){//要修改的是引用数据类型的//方法一完整替换很麻烦//state.person{name:小明,age:25,salary:8000}//方法二深复制将要修改的属性值放在后面将前面的属性值覆盖更好一些state.person{...state.person,money:8000}},changeArr(state){//方法一完整替换与对象一样//方法二深复制不能像对象一样覆盖let narr[...state.arr]narr[0]wstate.arrnarr}} })export default store组件中调用this.$store.commit(mutation名字) //组件中 this.$store.commit( mutation名字 )2.载荷payload mutations中是可以传参数的第一个参数是state第二个参数是自定义的需要的参数同样在组件中提交的时候也要有第二个参数this.$store.commit(函数名,第二个参数)。 可以向 store.commit 传入额外的参数即 mutation 的载荷payload) //index.js文件 mutations: {increment (state, n) {state.count n} }//调用 this.$store.commit(increment, 10)大多数情况下载荷应该是一个对象这样可以包含多个字段并且记录的 mutation 会更易读 mutations: {increment (state, payload) {state.count payload.amount} } //调用 this.$store.commit(increment, {operate:add,amount:500})3.有payload时以对象风格的提交方式 如果有payload的话更推荐用对象风格的提交方式。 mutations: {increment (state, payload) { //此时payload是包含着type的state.count payload.amount} } //调用 this.$store.commit({type: increment,operation:add,amount: 10,//参数 })4.常量替代 Mutation 事件类型 在小型项目中会更麻烦但在大型项目中可以避免出错因为写字符串容易写错。至于用不用这种方法取决于公司之前的项目。 在store文件夹中新建一个文件mutations-type.js在里面单独定义一些名字。在mutations中使用的时候使用常量在提交的时候也用常量。 使用过程 1.mutations-type.js中定义名字并导出不是默认导出。 2.在index.js文件中导入。由于不是默认导出的导入时需要加{}。 3.在mutations中的使用 [ADD](state){}4.在组件中提交mutation时 先引入名字在提交时函数名直接变为变量名。this.$store.commit(ADD) //index.js文件中 import Vue from vue import Vuex from vuex import {ADD,MINUS} from ./mutation-type //2 导入 Vue.use(Vuex) const store new Vuex.Store({state: {count: 10},mutations:{//这里要加[]因为不加[]是字符串加[]才是变量//3 使用[ADD](state){return state.count},[MINUS](state){return state.count--}} })export default store//mutation-type.js文件中 //1 定义mutation的名字并导出 export const ADD add; export const MINUS minus;//App.vue文件中 //4 引入 import {ADD} from ./store/mutation-type export default{data(){return{msg:我是App组件}},mounted(){//5 使用ADDthis.$store.commit(ADD)console.log(this.$store.state.count)//11},5.Mutation 必须是同步函数 比如个人信息需要在项目中通用需要请求得到 为何mutation不能包含异步操作 使用层面代码更高效易维护, 逻辑清晰规范而不是逻辑的不允许 具体原因为了让devtools 工具能够追踪数据变化 具体原因详解 每个mutation执行完成后都会对应到一个新的状态变更这样devtools就可以打个快照存下来每次状态的改变都会生产一个全新的 state 对象然后就可以实现 “time-travel” 了。如果mutation支持异步操作就没有办法知道状态是何时更新的无法很好的进行状态的追踪给调试带来困难。 注 vue-devtools 的时间旅行 - time travel Vuex 借鉴 Flux 单向数据流思想采用集中式统一管理保存状态。但是这些状态不会随时间改变而变化。为了使状态可以被捕获、重播或重现。vue-devtools工具可以帮助我们的 Vue 应用可以实现这种时间旅行 每次状态的改变都会生产一个全新的 state 对象当你想展现什么时间段的状态只需要切换到那个时间段的 state 对象所以vuex原则上只能通过mutation 并且非异步更改状态否则无法实现state修改的记录保留或无法正确记录。 actions actions用于写异步操作异步操作之后提交mutation修改数据。 有一个默认参数context上下文对象实际上就是与store对象一模一样的对象. 在其他组件中派发actionthis.$store.dispatch(actions中函数名) Action 类似于 mutation不同在于 Action 提交的是 mutation而不是直接变更状态。只有mutation能修改state数据Action 可以包含任意异步操作。 演示代码 const store new Vuex.Store({state: {info:我是共享的数据},mutations: {changeInfo (state,payload) {state.infopayload.msg}},actions: {//可以使用es6的结构赋值来进行简化getInfo (context,payload) {//这里只是将异步操作做了然后再将修改state数据的操作交还给mutation只有mutation能修改state数据。setTimeout((){context.commit(changeInfo,payload)},3000)}} })//其他组件中派发actions this.$store.dispatch(getInfo,{msg:helloworld})Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象因此你可以调用 context.commit 提交一个 mutation或者通过 context.state 和 context.getters 来获取 state 和 getters。 **其他组件分发action**最终mutation可以接收到其他组件dispatch的参数。 this.$store.dispatch(increment) //带参数的形式// 以载荷形式分发 this.$store.dispatch(incrementAsync, {amount: 10 })// 以对象形式分发 this.$store.dispatch({type: incrementAsync,amount: 10 })如果只用commit操作常用es6的结构赋值来简化也可以带载荷 actions:{getInfo({commit}){setTimeout((){commit(changeInfo,{aa:helloworld})},3000)} }**组合action**有两个action先触发其中一个等到这个有返回结果之后再去触发另一个action。话不是很理解的 1.dispatch函数返回值是promise 如需要先拿到Id再用id去拿到info最后根据info再去修改state的数据。 //index.js文件中 需要先执行getId再执行getInfo最后resolve的值传到了getInfo中的payload中再去修改state的值 actions:{getInfo(context,payload){console.log(payload)},getId(){return new Promise((resolve){setTimeout(() {resolve(我是id)}, 2000);})} }//其他组件中 先分发getId返回一个Promise再分发getInfo changeInfo(){this.$store.dispatch(getId).then((res){this.$store.dispatch(getInfo,res)}) }//index.js文件中 actions: {actionA ({ commit }) {return new Promise((resolve, reject) {setTimeout(() {commit(someMutation)resolve()}, 1000)})} }现在你可以 //其他组件中 this.$store.dispatch(actionA).then(() {// ...this.$store.dispatch() })在另外一个 action 中也可以 actions: {// ...actionB ({ dispatch, commit }) {return dispatch(actionA).then(() {commit(someOtherMutation)})} }最后如果我们利用 async / await 我们可以如下组合 action // 假设 getData() 和 getOtherData() 返回的是 Promiseactions: {async actionA ({ commit }) {commit(gotData, await getData())},async actionB ({ dispatch, commit }) {await dispatch(actionA) // 等待 actionA 完成commit(gotOtherData, await getOtherData())} }mutaions和actions流程 modules 在不开启命名空间的默认情况下只有state数据是只属于模块的在读取数据时默认情况下state读取的是根实例的getters、mutations、actions默认是定义在全局的若想把getters、mutations、actions也设置为私有的给模块开启命名空间。 各个模块中state、mutation、actions中的变量名可以重复getters中的方法名不能重复。 基本用法 Vuex 允许我们将 store 分割成模块module。每个模块拥有自己的 state、mutation、action、getter 单独定义一个模块跟我们之前定义store是一样的 store文件夹下的moduleA.js 默认导出 export default{state:{text:我是moduleA的数据},getters:{},mutations:{},actions:{} }store文件夹下的moduleB.js 默认导出 export default{state:{text:我是moduleB的数据},getters:{},mutations:{},actions:{} }store文件夹下的index.js 导入store模块 import Vue from vue; import Vuex from vuex; import moduleA from ./moduleA import moduleB from ./moduleB Vue.use(Vuex); const storenew Vuex.Store({state:{ },modules:{// 模块名:模块对象moduleA,moduleB} })export default store读取模块中的数据语法默认情况下是根实例的state想要读取子模块的state需要指明模块名this.$store.state.模块名.数据名 this.$store.state.模块名.数据名 //例如 this.$store.state.moduleB.text多层嵌套 每一个子模块依旧可以有自己的子模块比如moduleA里添加一个moduleC moduleA.js import moduleC from ./moduleC export default{state:{text:我是moduleA的数据},getters:{},mutations:{},actions:{},modules:{moduleC} }moduleC.js export default{state:{text:我是moduleC的数据},getters:{},mutations:{},actions:{} }访问this.$store.state.模块名.子模块名.数据名 this.$store.state.模块名.子模块名.数据名 //例如 this.$store.state.moduleA.moduleC.text命名空间 不开启命名空间在默认情况下模块内部的 action、mutation 和 getter 是注册在全局命名空间的 比如moduleA和moduleB都定义了一个叫changeText的mutation提交mutation后所有模块的text数据都会发生更改。 moduleA.js import moduleC from ./moduleC export default{state:{text:我是moduleA的数据},getters:{},mutations:{changeText(state){state.textmoduleA的数据改了}},actions:{},modules:{moduleC} }moduleB.js export default{state:{text:我是moduleB的数据},getters:{},mutations:{changeText(state){state.textmoduleB的数据改了}},actions:{} }MyHome.vue computed:{textA(){console.log(this.$store.state)return this.$store.state.moduleA.text},textB(){console.log(this.$store.state)return this.$store.state.moduleB.text}},methods:{//我们会发现我们直接提交mutation不需要加模块名字A和B的mutation都能触发changeText(){this.$store.commit(changeText)}}getters也是同理多个模块都有同一个getter默认读取的是根store的getters如果根store中没有则按照模块注册顺序读取 **开启命名空间后**getters、mutations、actions只在当前模块内有效。 开启命名空间 可以通过在模块内部添加 namespaced: true 的方式使其成为带命名空间的模块表示这些只在当前模块生效。 当模块被注册后它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名 如果是只给moduleA开启了命名空间像以前一样提交mutation时this.$store.commit(mutation方法名)只有muduleA的数据没有发生更改。 如果只想要提交moduleA的mutationthis.$store.commit(模块名/mutation方法名)这时只有modualA的数据发生了更改。 示例 moduleA.js import moduleC from ./moduleC export default{namespaced: true, //开启命名空间state:{text:我是moduleA的数据},getters:{info(){return 哈哈}},mutations:{changeText(state){state.textmoduleA的数据改了}},actions:{},modules:{moduleC} }// 其他组件中 this.$store.commit(changeText)//除了moduleA都发生了更改 this.$store.commit(moduleA/changeText) //只有moduleA的数据发生了更改此时修改数据需要加上模块名 this.$store.commit(moduleA/changeText)//代表提交moduleA里的changeText //对于嵌套模块 this.$store.commit(moduleA/moduleC/changeText)//提交moduleA里的moduleC里的changeText//对于getters注意这里的不同getters不是方法 this.$store.getters[moduleA/info] //对于actions this.$store.dispatch(moduleA/actionA)开启命名空间后访问全局内容 在开启了命名空间的模块内部也是可以访问到全局数据的 getters中可以拿到全局的state和gettersgetters中的第三四个参数 rootState rootGetters 拿到的是所有的数据不只是根store中的数据 someGetter (state, getters, rootState, rootGetters) {getters.someOtherGetter // - foo/someOtherGetterrootGetters.someOtherGetter // - someOtherGetter},actions中可以拿到所有的state和getterscontext里面就有全局的 actions:{actionA(context){console.log(context)}},输出内容 在开启了命名空间的模块内部也可以提交全局的action或者mutation实现更改全局的而开启命名空间的不更改 将 { root: true } 作为第三个参数传给 dispatch 或 commit 即可表示提交的是全局的第二个参数是actions和mutations需要传的参数没有就写null。 想要更改全局的action或者mutation开启了命名空间的模块不做修改 1、开启命名空间在组件中使用时正常使用this.$store.dispatch(actions方法名) 2、在开启了命名空间的模块内部在提交的时候传{ root: true }作为第三个参数。 dispatch(someOtherAction) // - foo/someOtherAction 调用的是当前模块的dispatch(someOtherAction, null, { root: true }) // - someOtherActioncommit(someMutation) // - foo/someMutationcommit(someMutation, null, { root: true }) // - someMutation关于命名空间全局访问局部、局部访问局部、局部访问全局都是可以的。 带命名空间的辅助函数 ...mapState(moduleA,{textA:text}) ...mapMutations(moduleA,[changeText])...mapState(moduleA/moduleC,[text]),还可以通过使用 createNamespacedHelpers 创建基于某个命名空间辅助函数。它返回一个对象对象里有新的绑定在给定命名空间值上的组件绑定辅助函数 import { createNamespacedHelpers } from vuex const { mapState } createNamespacedHelpers(moduleA/moduleC)computed:{...mapState([text]),//这样text默认就是在moduleA/moduleC下的}辅助函数 使用步骤 1、引入mapState 把vuex中的数据映射到组件中 import { mapState,mapGetters,mapMutations,mapActions } from vuexmapState函数的返回值是一个对象 初步优化公司里肯定不会这么写 //把this.$store.state做了封装 computed:mapState({money:statestate.moneya:statestate.a })二次优化99%不会这么写但也有可能这么写是因为vuex数据的名字与组件中之前写的某些变量名重复了需要改名这时可以二次优化和最终优化结合起来写 computed:mapState({//前面是组件中计算属性的名字 后面是vuex中的名字 money:money,// 必须是字符串的形式a:a,b:b,c:c,})最终优化工作中推荐前提是计算属性中的名字与vuex中state的名字一样 computed:mapState([money,a,b,c])//使用扩展运算符将辅助函数和其他计算属性混合到一起组成一个对象 data(){return{count:100,gender:1} }, //mapState computed:{...mapState([money,a,b,c]),//最终优化...mapState({change:d}),//二次优化需要将vuex映射过来的数据改名的情况...mapGetters([doubleA,doubleB]),//sex(){return this.gender1?男:女}},注意如果getters需要传参的话在映射到computed中时也可以直接写数组然后在html模板中直接传入参数即可同理mutation和action如果有载荷的话也是这样。 使用案例 // store/index.js import Vue from vue; import Vuex from vuex; Vue.use(Vuex);const store new Vuex.Store({state: {count: 10},getters:{doubleCount(state){return (rate){return state.count*rate}}},mutations:{changeCount(state,payload){state.count*payload.count}},actions:{asyncChangeCount({commit},payload){setTimeout(() {commit(changeCount,payload)}, 3000);}} }); export default store!-- 组件中 -- templatediv!-- getters、mutations、actions如果有需要传参数的直接在模板中调用的时候传参即可在mapGetters中和mapState一样直接写数组 --h1{{count}}----{{doubleCount(10)}}/h1h1{{num}}/h1button clickchangeCount({count:5})更改/buttonbutton clickasyncChangeCount({count:10})异步更改/button/div/templatescript import { mapActions, mapGetters, mapMutations, mapState } from vuexexport default {computed:{...mapState([count]),...mapState({num:count}), // 使用对象格式更改名字...mapGetters([doubleCount]),} ,methods:{...mapMutations([changeCount]),...mapActions([asyncChangeCount])}} /scriptstyle scoped/style vuex不是永久存储一刷新就没有了只是临时过度的。如果想要刷新浏览器不丢失数据只有存储到本地存储LocalStorage、SessionStorage、cookies或数据库中。
http://www.dnsts.com.cn/news/88172.html

相关文章:

  • 专业电子网站建设江西赣建建设监理网站
  • 域名注册完成后如何做网站外国的购物平台
  • 淮安网站建设多少钱企业网站开发前台模块设计
  • 企业网站托管外包平台怎么样推广网站
  • 学网站开发多少钱户外用品网站建设项目背景
  • asp网站静态化php仿百度网站源码
  • lnmp网站开发企业cms源码
  • 保洁公司网站模板网站备案百度站长提交
  • 网站建设方案服务器网站免费正能量直接进入app
  • 万年历网站做北京商场核酸
  • 资阳市网站建设百度怎么做关键词优化
  • 外贸网站 费用北京网站开发团队
  • 设计办公室设计公司常州百度推广排名优化
  • 任县建设局网站自定义wordpress首页标题
  • 做盗版网站违法吗备案空壳网站通知
  • 网站例子大全如何写一份网站优化建设的方案
  • 铜陵网站建设公司代码给wordpress添加图片不显示
  • 邢台做wap网站价格网站哪家做的比较好
  • 建设网站公司浩森宇特网站如何管理
  • 高端营销型企业网站建设wordpress广告联盟
  • 廊坊网站建设推广服务关于我们 网站
  • 宁波做360网站推广wordpress模板+保险
  • 做网站需要哪些素材建网站哪个公司好
  • 网站搭建岗位及要求wordpress优化数据
  • 专门找图片素材的网站wordpress首页主标题移到后面
  • 知名的网站制作公司需要多少钱点击图片是网站怎么做
  • 左旗网站建设ico交易网站怎么做
  • 徐州h5模板建站网站建设需要写语句吗
  • 论坛网站如何建设哪个网站可以付费做淘宝推广
  • 国外的服务器网站企业官方网站格式