route
1、 传统web应用vs单页面web应用
1.1、传统web应用
传统web应用,又叫做多页面web应用:核心是一个web站点由多个HTML页面组成,点击时完成页面的切换,因为是切换到新的HTML页面上,所以当前页面会全部刷新。
1.2、单页面web应用(SPA:Single Page web Application)
整个网站只有一个HTML页面,点击时只是完成当前页面中组件的切换。属于页面局部刷新。
单页应用程序 (SPA) 是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。浏览器一开始会加载必需的HTML、CSS和JavaScript,所有的操作都在这张页面上完成,都由JavaScript来控制。单页面的跳转仅刷新局部资源。因此,对单页应用来说模块化的开发和设计显得相当重要。
1.3、单页面应用的优缺点:
1.3.1、单页面应用的优点
1、提供了更加吸引人的用户体验:具有桌面应用的即时性、网站的可移植性和可访问性。
2、单页应用的内容的改变不需要重新加载整个页面,web应用更具响应性和更令人着迷。
3、单页应用没有页面之间的切换,就不会出现“白屏现象”,也不会出现假死并有“闪烁”现象
4、单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍。
5、良好的前后端分离。后端不再负责模板渲染、输出页面工作,后端API通用化,即同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端
1.3.2、单页面应用的缺点:
1、首次加载耗时比较多。
2、SEO问题,不利于百度,360等搜索引擎收录。
3、容易造成CSS命名冲突。
4、前进、后退、地址栏、书签等,都需要程序进行管理,页面的复杂度很高,需要一定的技能水平和开发成本高。
1.3.3、单页面和多页面的对比
目前较为流行的是单页面应用的开发。
如果想使用Vue去完成单页面应用的开发,需要借助Vue当中的路由机制。
2、 路由route与路由器router
1、路由:route
2、路由器:router
路由器用来管理/调度各个路由
对于一个应用来说,一般路由器只需要一个,但是路由是有多个的
3、每一个路由都由key和value组成。
key是路径,value是对应的组件
key1+value1===>路由route1
key2+value2===>路由route2
key3+value3===>路由route3
......
4、路由的本质:一个路由表达了一组对应关系。
5、路由器的本质:管理多组对应关系。
3、 使用路由
3.1、创建组件
app.vue
<template><div class="app"><MyHeader class="myheader" title="首页" /><Home class="mycontent" /><Myfooter class="myfooter" /></div>
</template><script>
import MyHeader from './components/MyHeader.vue'
import Myfooter from './components/Myfooter.vue';
import Home from './components/home.vue';
export default {name: 'App',components: {MyHeader,Myfooter,Home}
}
</script><style>
* {margin: 0;padding: 0;
}.app {width: 375px;height: 667px;display: flex;flex-direction: column;margin: 30px auto;
}.myheader,
.myfooter {width: 100%;line-height: 50px;background-color: gainsboro;display: flex;align-items: center;
}.myheader {justify-content: space-between;
}.myfooter {justify-content: space-around;
}.mycontent {width: 100%;flex-grow: 1;background-color: pink;
}
</style>
MyHeader.vue
<template><div class="myheader"><button>返回</button><h3>{{ title }}</h3><button>详情</button></div>
</template><script>
export default {name:'MyHeader',props:['title']}
</script><style scoped>
button{width: 70px;height: 40px;
}</style>
MyFooter.vue
<template><div><a href="#" v-for="nav in navList" :key="nav">{{ nav }}</a></div>
</template><script>
export default {name: 'MyFooter',data() {return {navList: ['首页', '新闻', '购物车', '我的']}},}
</script><style></style>
Home.vue
<template><div>home</div>
</template><script>
export default {name:''}
</script><style></style>
3.2、安装路由vue-router
(1) vue2 要安装 vue-router3
① npm i vue-router@3
(2) vu3要安装vue-router4
① npm i vue-router@4
如果报错
npm i vue-router@3 --legacy-peer-deps
3.3、配置vue-router环境并使用
main.js
import Vue from "vue";
import App from "./App.vue";Vue.config.productionTip = false;
// 导入路由器对象
import router from "./router";const vm = new Vue({render: (h) => h(App),// 一旦使用了vue-router插件,那么new Vue的时候就可以直接传递一个配置项// 注册路由器对象router
}).$mount("#app");
console.log(vm);
在src目录下,新建一个router文件夹,新建index.js,配置路由器对象,并暴露
第一步:配置路由关系
// 导入Vue
import Vue from "vue";
// 导入VueRouter
import VueRouter from "vue-router";
// 注册VueRouter
Vue.use(VueRouter)// 导入路由组件
import Home from "@/views/home.vue";
import News from "@/views/news.vue";
import Car from "@/views/car.vue";
import My from "@/views/my.vue";const router=new VueRouter({// 配置路由规则 配置一组组路由关系,// 每一组路由关系都是一个对象:// key:路径==>path// value:组件==>componentroutes:[{path:'/home',//注意要以/开头component:Home},{path:'/news',component:News},{path:'/car',component:Car},{path:'/mine',component:My},]})export default router
第二步:使用路由关系
MyFooter.vue
<template><div><!-- 第二步:routerlink的to属性,配置好路由关系 --><!-- to 配置路由路径 ,点击时会跳到对应路径的路由组件--><router-link :to="nav.path" v-for="nav in navList" :key="nav.name">{{ nav.name }}</router-link><!-- <a href="#" >{{ nav }}</a> --></div>
</template><script>
export default {name: 'MyFooter',data() {return {navList: [{name: '首页',path: '/home',},{name: '新闻',path: '/news',},{name: '购物车',path: '/car',},{name: '我的',path: '/mine',},]}},}
</script><style></style>
第三步:路由组件显示
app.vue
<template><div class="app"><MyHeader class="myheader" title="首页" /><!-- <Home class="mycontent" /> --><!-- 第三步:告诉路由器,路由组件显示的位置 --><div class="mycontent"><!-- 告诉路由器,路由组件显示在这个位置 --><router-view /></div><Myfooter class="myfooter" /></div>
</template>
注意事项:
① 路由组件一般会和普通组件分开存放,路由组件放到pages或views目录,普通组件放到components目录下。
② 路由组件在进行切换的时候,切掉的组件会被销毁,可用destroyed生命周期钩子证实
③ 路由组件的两个属性:$route和$router
1) $route:属于自己的路由对象。
2) $router:多组件共享的路由器对象。
3.4、小功能:
点击底部导航,顶部title部分随着进行更新,这里用到了兄弟传参,还要在本地保存一份,解决刷新,title初始化的问题,
注意:router-link上不能绑定点击事件,不生效
myfooter.vue
<template><div><!-- 第二步:routerlink的to属性,配置好路由关系 --><!-- to 配置路由路径 ,点击时会跳到对应路径的路由组件--><router-link :to="nav.path" v-for="nav in navList" :key="nav.name" active-class="active"><span @click="sendTilte(nav.name)">{{ nav.name }}</span></router-link><!-- <a href="#" >{{ nav }}</a> --></div>
</template><script>
export default {name: 'MyFooter',data() {return {navList: [//·····]}},methods: {sendTilte(name) {this.$bus.$emit('handlerSendTilte', name)localStorage.setItem('title',name)}}}
</script>
myheader.vue
<template><div class="myheader"><button>返回</button><h3>{{ title }}</h3><button>详情</button></div>
</template><script>
export default {name: 'MyHeader',data() {return {// 初始化数据从本地拿取title: localStorage.getItem('title')||'首页'}},mounted() {this.$bus.$on('handlerSendTilte', (name) => {this.title = name})}
}
</script>
4、 多级路由
第一步:创建好二级路由组件
第二步:router/index.js配置好二级路由关系
//....import Hot from "@/views/home/hot.vue";import Agree from "@/views/home/agree.vue";import More from "@/views/home/more.vue";const router = new VueRouter({// 配置路由规则 配置一组组路由关系,// 每一组路由关系都是一个对象:// key:路径==>path// value:组件==>component// 第一步:配置好路由关系:key--valueroutes: [{path: '/home',//注意要以/开头component: Home,// children配置项,配置二级路由children: [{// path写法一:路径完整// path:'/home/hot',//二级路由路径// path写法二:直接写路径名,不能加/path: 'hot',component: Hot//二级路由},{path: 'agree',component: Agree},{path: 'more',component: More}]},//·····
第三步:routerLink使用
src/views/home/index.vue
<template><div><!-- 轮播图 --><div class="swiper">轮播图</div><!-- 二级导航 --><div class="subNav"><!-- 二级路由在使用时,必须把路径写完整 --><router-link to="/home/hot"><h5>正在热卖</h5></router-link><router-link to="/home/agree"><h5>值得推荐</h5></router-link><router-link to="/home/more"><h5>查看更多</h5></router-link></div>//·····
第四步:设置二级路由显示位置
<template><div><!-- 轮播图 --><div class="swiper">轮播图</div><!-- 二级导航 --><div class="subNav">//·····</div><!-- 路由组件显示位置 --><div><router-view /></div></div>
</template>
5、 路由起名字
可以给路由起一个名字,这样可以简化to的编写,且后期我们在prams传参,需要用到name
第一步:在路由关系中,添加name的配置
{path: 'agree',component: Agree,name: 'agree'},
第二步:使用name,简化to的写法
<!-- 二级导航 --><div class="subNav"><!-- 二级路由在使用时,必须把路径写完整 --><!-- to的写法一 --><!-- <router-link to="/home/hot"> --><!-- to的写法二 --><!-- <router-link :to="{path:'/home/hot'}"> --><!-- to的写法三 --><router-link :to="{ name: 'hot' }"><h5>正在热卖</h5></router-link><router-link to="/home/agree"><h5>值得推荐</h5></router-link><router-link to="/home/more"><h5>查看更多</h5></router-link></div>
6、 路由query传参
为了提高组件的复用性,可以给路由组件传参
传递参数:哪里点击跳转,在哪里传参数
需求:根据电影列表信息,点击不同的电影,查看不同的详情页面
第一步:配置好详情页组件
views/detail.vue
<template><div><h1>detail</h1></div>
</template><script>
export default {// 接收传递参数mounted(){// 当前的路由信息console.log(this.$route.query,'route');}
}
</script><style></style>
第二步:router/index.js
routes: [{//路由重定向path: '/',//初始路径redirect: '/home/hot'},{path:'/detail',name:'detail',component:Detail},//·····
第三步:传递参数,哪里点击,哪里传递
<template><div><ul><li v-for="film in films" :key="film.filmId"><!-- query传参to="/路由路径?参数名=参数值&参数名=参数值"--><!-- 1、传递静态参数 --><!-- <router-link to="/detail?filmId=123" class="film"> --><!-- 2、传递从data中读取的参数 --><!-- <router-link :to="`/detail?filmId=${num}`" class="film"> --><!-- 3、传递遍历的参数 --><!-- <router-link :to="`/detail?filmId=${film.filmId}&num=${num}`" class="film"> --><!-- 4、以对象的方式传递参数 --><router-link :to="{// path: '/detail',name: 'detail',query: {filmId: film.filmId,num: num}}" class="film"><img :src="film.poster" alt="" style="width: 100px;">{{ film.name }}</router-link></li></ul></div>
</template>
第四步:拿取数据
拿到detail组件的路由 this.$route.query ,里面就有传递的参数
<template><div><h1>detail:{{ filmId }}</h1></div>
</template><script>
export default {data() {return {filmId: ''}},// 接收传递参数mounted() {// 当前的路由信息console.log(this.$route.query, 'route');this.filmId = this.$route.query.filmIdconsole.log(`通过filmId:${this.filmId}请求数据,进行展示`);}
}
</script>
7、 路由params传参
第一步:新建好detail组件,并配置好路由关系
如果是采用to传递字符串的形式拼接参数: to='路径名/参数1/参数2' ,必须在route/index.js中路径处进行占位
{// params传递,必须在路由后进行参数占位path:'/detail/:filmId/:num2',name: 'detail',component: Detail},
如果是to传递对象的形式:可以不占位
{// params传递,必须在路由后进行参数占位// path:'/detail/:filmId/:num2',// 如果是对象的形式传参,就不需要占位path: '/detail',name: 'detail',component: Detail},
第二步:传递参数
哪里点击,哪里传递参数
<template><div><ul><li v-for="film in films" :key="film.filmId"><!-- params传参to='路径名/参数1/参数2' --><!-- 1、传递静态数据 --><!-- <router-link to="/detail/123/456" class="film"> --><!-- 2、传递动态的数据 --><!-- <router-link :to="`/detail/${film.filmId}/456`" class="film"> --><!-- 3、传递参数:对象的形式,不能用path,必须用name --><router-link :to="{// path: '/detail',name: 'detail',params: {filmId: film.filmId,num2: 456}}" class="film"><img :src="film.poster" alt="" style="width: 100px;">{{ film.name }}</router-link></li></ul></div>
</template>
第三步:detail组件接收参数
拿到当前组件的路由关系:this.$route.params
<template><div><h1>detail:{{ filmId }}</h1></div>
</template><script>
export default {data() {return {filmId: ''}},// 接收传递参数mounted() {// 当前的路由信息console.log(this.$route.params);this.filmId=this.$route.params.filmId// console.log(`通过filmId:${this.filmId}请求数据,进行展示`);}
}
</script>
8、 路由的props
props配置主要是为了简化query和params参数的接收。让插值语法更加简洁。
哪个组件接收参数,就在哪个组件路由关系中配置props
三种写法:对象,函数,布尔值写法
// 创建路由器对象(在路由器对象中配置路由)
const router = new VueRouter({routes: [// 路由1{name: "sub1",path: "/subject1/:a1/:a2/:a3",component: subject,//第一种写法,对象的写法。只能传递固定值// props: { // x: "章三",// y: "李四",// z: "王二麻",// },//第二种写法:函数式,这里的$route就是当前路由// props($route) {// return {// a1: $route.params.a1,// a2: $route.params.a2,// a3: $route.params.a3,// };// },//第三种写法:直接将params方式收到的数据转化为props,这种方式,只针对params传参props:true },{name: "sub2",path: "/subject2/:a1/:a2/:a3",component: subject,},],
});
// 暴露路由器对象
export default router;
subject.vue props接收,直接可以使用
<template><div><ul class="web"><li>{{ a1 }}</li><li>{{ a2 }}</li><li>{{ a3 }}</li></ul></div>
</template><script>
export default {name: 'web',// 接收路由器中配置的props,简写插值语法的写法//props: ['x', 'y', 'z']props: ['a1', 'a2', 'a3']
}
</script>
<style>
.web {background-color: pink;
}
</style>
9、 router-link的replace属性
9.1、栈数据结构,先进后出,后进先出原则
9.2、浏览器的历史记录是存储在栈这种数据结构当中的。包括两种模式:
(1) push模式(默认的)
(2) replace模式
(3) 如何开启replace模式:
a.<router-link :replace=”true”/>
b. <router-link replace />
10 、编程式路由导航
需求中可能不是通过点击超链接的方式切换路由,也就是说不使用如何实现路由切换。
这种方式,我们叫声明式的路由导航
通过编写代码,完成路由组件的切换,这种方式我们呢交编程式路由导航
声明式路由导航可以通过相关API来完成:
(1) push模式:
this.$router.push({
name : ‘’,
query : {}
})
(2) replace模式:
this.$router.replace({
name : ‘’,
query : {}
})
(3) 前进:
this.$router.forward()
(4) 后退:
this.$router.back()
(5) 前进或后退几步:
this.$router.go(2) 前进两步
this.$router.go(-2) 后退两步
(6) 使用编程式路由导航的时候,需要注意:
重复执行push或者replace的API时,会出现以下错误:
这个问题是因为push方法返回一个Promise对象,期望你在调用push方法的时候传递两个回调函数,一个是成功的回调,一个是失败的回调,如果不传就会出以上的错误。所以解决以上问题只需要给push和replace方法在参数上添加两个回调即可。
<button @click="$router.forward()">前进</button>
<button @click="$router.go(1)">go-1</button>
<button @click="$router.go(2)">go-2</button>
<button @click="$router.back()">返回</button>
<button @click="$router.go(-1)">go-1</button>
<button @click="$router.go(-2)">go-2</button>
<button @click="goDetail(film.filmId)">跳转详情页</button>
//····goDetail(filmId) {//有历史记录this.$router.push({// path:'/detail',name: 'detail',params: {filmId: filmId,num2: 456},query: {filmId: filmId,num2: 456}}, () => { }, () => { })// 没有历史记录// this.$router.replace({// // path:'/detail',// name: 'detail',// params: {// filmId: filmId,// num2: 456// }// }, () => { }, () => { })}
11、 缓存路由组件
默认情况下路由切换时,路由组件会被销毁。有时需要在切换路由组件时保留组件(缓存起来)。
<keep-alive>//会缓存所有的路由组件
<router-view/>
</keep-alive>
通过添加以下3种属性,控制路由组件的缓存
include - 字符串或正则表达式或变成动态的属性,解析数组。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式或变成动态的属性,解析数组。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
注意:router.js 中的name和vue组件的name需要保持一致
<div class="mycontent"><!-- 告诉路由器,路由组件显示在这个位置 --><!-- 1、只想news组件被缓存,其他组件切换时,还是被销毁 include--><!-- 2、除了car组件,其他组件都被销毁 exclude --><!-- <keep-alive include="news"> --><!-- <keep-alive :include="['news']"> --><keep-alive :exclude="['news']" ><router-view /></keep-alive></div>
12 activated和deactivated
对于普通的组件来说,有8个生命周期函数,对于路由组件, 除了常规的8个,额外还有2个,
<keep-alive>
包裹的路由组件,该组件有两个特有的生命周期函数:activated
和deactivated
。
activated
在路由组件被激活时触发;
deactivated
在路由组件失活时触发。
这两个钩子函数的作用是捕获路由组件的激活状态。
<template><div><ul class="web"><li><input type="checkbox">html</li><li><input type="checkbox">css</li><li><input type="checkbox">js</li></ul></div>
</template><script>
// 需求:当组件切换到subject1的时候,每隔1s,输出一句话‘工作中····’
// 当组件切走时,输出‘休息中····’,并解除定时器
// 正常情况下,这个功能可以用mounted和beforeDestroy去完成,但当subject1组件用keep-alive保持激活时,
// 就必须使用activated和deactivated组件了
export default {name: 'subject1',// mounted() {// this.timer = setInterval(() => {// console.log('工作中····');// }, 1000)// },// beforeDestroy() {// console.log('休息中···');// clearInterval(this.timer)// }// activated() {this.timer = setInterval(() => {console.log('工作中····');}, 1000)},deactivated() {clearInterval(this.timer)console.log('休息中');}
}
</script>
<style>
.web {background-color: pink;
}
<
13、 路由守卫
1、面试:有哪些路由守卫?
2、实际开发过程中,重点全局前置守卫
不同的守卫其实就是在不同的时机,不同的位置,添加鉴权(鉴别权限)代码
13.1 全局前置守卫
需求:只有当用户是admin时,允许切换到subject2路由上
1、书写位置:在创建好router之后,以及暴露router之前
2、执行时机:beforeEach()中传入一个回调函数callback,可以是普通函数或箭头函数都可以,在初始化时执行一次,然后每一次在切换任意组件之前都会被调用
router.beforeEach((to, from, next)=>{ // 翻译为:每次前(寓意:每一次切换任意路由之前执行。)
// to 去哪里(to.path、to.name)
// from 从哪来
// next 继续:调用next( )
})
3、callback函数有3个参数:to from next
from参数:from是一个路由对象,表示从哪里来(从那个路由切过来的),起点
to参数:to也是一个路由对象,表示到哪里去,终点
next参数:是一个函数,调用这个函数之后,表示放行,可以继续向下走
4、给路由对象添加自定义属性的话,需要在路由对象的meta(路由元)中定义
如果路由组件较多。to.path会比较繁琐,可以考虑给需要鉴权的路由扩展一个布尔值属性,可以通过路由元来定义属性:meta:{isAuth : true}
// 创建路由器对象(配置一个个路由)
// 导入vue-router插件
import VueRouter from "vue-router";
// 导入组件
import subject1 from "../pages/subject1.vue";
import subject2 from "../pages/subject2.vue";// 创建路由器对象(在路由器对象中配置路由)
const router = new VueRouter({routes: [// 路由1{name: "sub1",path: "/subject1",component: subject1,},// 路由2{name: "sub2",path: "/subject2",component: subject2,// 带有isAuth属性,并且属性值为ture的,需要鉴权meta: { isAuth: true },},],
});
// 全局前置路由守卫
// 1、书写位置:在创建好router之后,以及暴露router之前
// 2、执行时机:beforeEach()中传入一个回调函数callback,可以是普通函数或箭头函数都可以,
// 在初始化时执行一次,然后每一次在切换任意组件之前都会被调用
// 3、callback函数有3个参数:to from next
// from参数:from是一个路由对象,表示从哪里来(从那个路由切过来的),起点
// to参数:to也是一个路由对象,表示到哪里去,终点
// next参数:是一个函数,调用这个函数之后,表示放行,可以继续向下走
// 4、给路由对象添加自定义属性的话,需要在路由对象的meta(路由元)中定义
router.beforeEach((to, from, next) => {// console.log(to);// 需求:只有当用户是admin时,允许切换到subject2路由上let loginName = "admin1";//1、 判断路由组件的name// if (to.name == "sub2") {//2、 判断路由组件的path// if (to.path == "/subject2") {// 3、可以在路由对象中自定义个属性,需要鉴权的组件都加上ture,不需要鉴权的,则是undefined,是falseif (to.meta.isAuth) {if (loginName == "admin") {next();} else {alert("对不起,你没有权限");}} else {next();}
});// 暴露路由器对象
export default router;
13.2 全局后置守卫
需求: 每次切换完路由组件后,更换title标题栏,在meta中设置title属性属性值
1、书写位置:router/index.js文件中拿到router对象,在创建router对象之后,暴露router对象之前写
2、执行时机:初始化执行一次,以后每一切换完任意路由之后
3、参数:只有to,from,没有next,因为没有必要了
router.afterEach((to, from)=>{ // 翻译为:每次后(寓意:每一次切换路由后执行。)
// 没有 next
document.title = to.meta.title // 通常使用后置守卫完成路由切换时title的切换。
})
该功能也可以使用前置守卫实现:
//需求: 每次切换完路由组件后,更换title标题栏,在meta中设置title属性属性值
// 书写位置:在创建router对象之后,暴露router对象之前
// 执行时机:初始化执行一次,以后每一切换完任意路由之后
// 参数:只有to,from,没有next,因为没有必要了
router.afterEach((to, from) => {document.title = to.meta.title || "欢迎使用";
});
13.3 局部路由守卫之path守卫(路由守卫)
beforeEnter(){}
书写位置:写在route对象中
执行时机:进入到对应路由组件前被调用
参数:to,from,next
注意:没有afterEnter
// 路由2{name: "sub2",path: "/subject2",component: subject2,// 带有isAuth属性,并且属性值为ture的,需要鉴权// meta: { isAuth: true, title: "subject2" },beforeEnter(to, from, next) {let loginName = "admin1";if (loginName == "admin") {next();} else {alert("对不起,没有权限");}},},
13.4 局部路由守卫之component守卫(组件守卫)
书写位置:写在路由组件当中,也就是xxx.vue文件中
执行时机: beforeRouteEnter 进去路由组件之前执行
beforeRouteLeave 离开路由组件之前执行
注意:只有路由组件才有这两个钩子。
<script>
export default {name: 'subject2',// 进去路由组件之前执行beforeRouteEnter(to, from, next) {console.log(`进入路由组件之前“${to.meta.title}`);next()},// 离开路由组件之前执行beforeRouteLeave(to, from, next) {console.log(`离开路由组件之前“${from.meta.title}`);next()}
}
</script>
14 、前端项目打包
源代码xxx.vue对于浏览器来说,浏览器只认识html,css,js
xxx.vue需要使用项目构建工具完成打包编译
例如,可以使用webpack来打包编译,生成html,css,js,这些浏览器才能识别
14.1、npm run build
1.、路径中#后面的路径称为hash。这个hash不会作为路径的一部分发送给服务器:(1)
http://localhost:8080/vue/bugs/#/a/b/c/d/e (真实请求的路径是:http://localhost:8080/vue/bugs)
2、路由的两种路径模式: hash模式和history模式的区别与选择
(1) hash模式
① 路径中带有#,不美观。
② 兼容性好,低版本浏览器也能用。
③ 项目上线刷新地址不会出现404。
④ 第三方app校验严格,可能会导致地址失效。
(2) history模式
① 路径中没有#,美观。
② 兼容性稍微差一些。
③ 项目上线后,刷新地址的话会出现404问题。需要后端人员配合可以解决该问题。
3.、默认是hash模式,如何开启history模式
(1) router/index.js文件中,在创建路由器对象router时添加一个mode配置项:
4. 项目打包
(1) 将Xxx.vue全部编译打包为HTML CSS JS文件。
(2) npm run build
相关文章:
route
1、 传统web应用vs单页面web应用 1.1、传统web应用 传统web应用,又叫做多页面web应用:核心是一个web站点由多个HTML页面组成,点击时完成页面的切换,因为是切换到新的HTML页面上,所以当前页面会全部刷新。 1.2、单页…...
设备监控---保障企业IT基础设施稳定运行
引言 在数字化转型的今天,企业的IT基础设施规模不断扩大,网络设备、服务器、存储系统、云资源等构成了复杂的IT环境。如何确保这些设备的高效运行,及时发现并解决潜在问题,成为IT运维团队的核心任务。设备监控---作为IT运维的基础…...
牙科CAD技术方案
本牙科CAD系统旨在打造一个数字化牙科设计的高性能CAD/CAM软件,提供从修复体设计(如牙冠、牙桥、贴面、活动义齿)到生产准备的全流程解决方案。系统整合多源数据(口内扫描、DICOM文件、颌骨运动数据等)实现精准设计&am…...
Shell编程之循环语句
目录 for循环语句 for语句的结构 for语句应用示例 根据姓名列表批量添加用户 根据IP地址列表检查主机状态 使用while循环语句 while语句的结构 while语句应用示例 批量添加规则编号的用户 猜价格游戏 until循环语句 until语句的结构 until语句应用示例 计算1-50的…...
ECMAScript 11 新特性
ECMAScript 11 新特性 ECMAScript 6 新特性(一) ECMAScript 6 新特性(二) ECMAScript 7~10 新特性 ECMAScript 11 新特性(本文) 1. 私有属性 在类的内部,通过在属性前添加 # 来表示私有属性。 …...
恶意外联情况监测-火绒、DNSLookupView(联网、禁用网卡、仅主机模式请求测试)
恶意外联情况监测-火绒、DNSLookupView(联网、断网、仅主机模式时的请求测试) 结论: 联网时: wireshark、火绒捕获 域名请求、IP请求 DNSLookupView捕获域名请求,无法捕获IP请求 禁用网卡时: 仅DNSLookupView捕获域名请求,无法捕获IP请求。…...
顺序表与Myarraylist
对于所有编程语言来说,数据结构都是精华 一个计算机程序数据结构算法; 我在之前的博客中写了关于集合框架与泛型,这就是数据结构的开始,我今天说的便是数据结构的第一个线性数据结构--顺序表 顺序表是一种线性数据结构…...
Redis 版本变更的变化
Redis 版本变更的变化 以下是 Redis 主要版本的清单及其核心功能变化的梳理,按时间顺序整理关键版本演进 8版本没有整理: Redis 1.0 (2009) 初始版本:发布首个稳定版本,支持基本键值存储。 核心特性: 支持字符串&…...
kubernetes》》k8s》》ConfigMap 、Secret
configmap官网 ConfigMap是一种 API 对象,使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。ConfigMap将配置和Pod解耦,更易于配置文件的更改和管理。ConfigMap 并不提供保密或者加密功能。 如果你想存储的数据是机密的…...
【React】基本语法
基本语法 通过jsx的语法可以在js中写html函数组件 / class组件的语法、父子组件传参、事件react 生命周期根据状态(数据)动态渲染组件 / 列表渲染 / 表单渲染class组件中的ref、ref回调函数 什么是react ? 用于构建用户界面的 JavaScript 库,主要用于构建…...
ubunut24.04 bash和zsh同时使用conda
文章目录 ubunut24.04 bash和zsh同时使用conda功能一、安装miniconda3二、bash中初始化conda以及安装命令补全1. bash中初始化conda2. bash中安装conda命令补全功能 三、zsh中初始化conda以及安装命令补全1. zsh中初始化conda2. zsh中安装conda命令补全功能3. 在~/.zshrc文件中…...
深度学习入门:神经网络
目录 1. 从感知机到神经网络1.1 神经网络的例子1.2 复习感知机1.3 激活函数登场 2 激活函数2.1 sigmoid函数2.2 阶跃函数的实现2.3 阶跃函数的图形2.4 sigmoid函数的实现2.5 sigmoid函数和阶跃函数的比较2.6 非线性函数2.7 ReLU函数 3 多维数组的运算3.1 多维数组 恒等函数soft…...
Unity有限制状态机FSM
我是标题 前言有限制状态机框架框架图:主要代码: 前言 一般的小型游戏的状态机会使用一个枚举类来枚举所有的状态,然后使用一个switch case来处理所有状态的行为逻辑,但是用这种方式会形成大量的冗余,因为所有的行为逻…...
bash的特性-命令和文件自动补全
在Linux或Unix操作系统中,Bash(Bourne Again SHell)是最常用的命令行解释器之一。它提供了丰富的功能来提升用户的交互体验,其中命令和文件名的自动补全是提高效率的一大利器。本文将详细介绍Bash中的自动补全功能,包括…...
聊聊价值投资
投资的必要性 如果手上现在有10w元,投资时间是50年,就算年化收益率只有15%,最终的财富值也会超过1亿元。而且通货膨胀会让你的存款购买力越来越少,如果你有无法及时花出去的钱,投资是必要的。05年的时候我家楼下的包子…...
ADI的BF561双核DSP怎么做开发,我来说一说(十六)触摸屏的设计
作者的话 ADI的双核DSP,最早的一颗是Blackfin系列的BF561,这颗DSP我用了很久,比较熟悉,且写过一些给新手的教程。 硬件准备 ADZS-BF561-EZKIT开发板:ADI原厂评估板 AD-ICE20000仿真器:ADI现阶段性能最好…...
基于labview的2PSK调制与解调
前面板如上图所示。 以上为产生随机序列的程序 以上为星座图程序 如需要源代码可联系我...
2021-11-01 C++输入十个数求最大最小和第二大第二小的值
缘由c语言输入十个数求最大最小和第二大第二小的值-编程语言-CSDN问答 这是个有意思的题目,考虑可扩展...如果是4个元素的数组,实现O(N)排序 void 输入十个数求最大最小和第二大第二小的值() {//缘由https://ask.csdn.net/ques…...
红人矩阵化运营策略:2025跨境电商如何高效布局海外红人营销
在全球社交媒体营销日益精细化的今天,跨境电商品牌正从单一红人合作转向系统化、团队化的“红人矩阵化运营”。尤其在TikTok、Instagram、YouTube等主流平台逐渐成熟的背景下,如何构建高效的海外红人营销矩阵,成为品牌实现全域曝光与精准转化…...
c# Kestrel
Kestrel 是 .NET 中用于 ASP.NET Core 应用程序的跨平台 Web 服务器。它是轻量级且高性能的,能够处理大量并发连接,常被用作 ASP.NET Core 应用的默认服务器。以下为你介绍 Kestrel 的基本使用和配置: 基本使用 创建一个简单的 ASP.NET Cor…...
算法训练之贪心
♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...
ThreeJs实现裸眼3D地球仪
一、实现效果 使用Three.js实现裸眼3D地球仪 二、实现代码 代码如下: <!DOCTYPE html> <html> <head><title>3D Earth</title><style>body { margin: 0; }canvas { display: block; }</style> </head> <body…...
0x07.Redis 的 hash 是什么?
回答重点: Redis 的 Hash 是一种键值对集合,允许将多个字段与其对应的值存储在同一个键中,从而方便管理和操作关联数据。它的主要特点包括: 高效存储:Hash 采用哈希表实现,能够在内存中高效地存储和操作小规模的数据集,非常适合存储对象的属性。快速操作:支持对字段的…...
今日一记:逆序打印字符、五人年龄计算、对N个数排序
今日进行三道题的练习 题目一:逆序打印字符 核心需求:将输入的n个字符以相反顺序输出。 算法分析: 递归思想: 递归函数先读取字符,直到输入结束(如换行符或EOF)。 在递归返回时打印字符&…...
【笔记】对抗训练-GAN
对抗训练-GAN 深度学习中 GAN 的对抗目标函数详解与最优解推导一、GAN 的基本对抗目标函数二、判别器与生成器的博弈目标三、判别器的最优解推导四、最优判别器的含义五、总结六、WGAN 的动机(为后续铺垫) 深度学习中 GAN 的对抗目标函数详解与最优解推导…...
Python六大数据类型与可变类型
数字类型包括整型(int),浮点型(float),布尔型(bool),复数型(complex)。整型只能存储整数,浮点型可以存储整数和小数,布尔型…...
回溯-day65
回溯 什莫事回溯 回溯法也可以叫做回溯搜索法,它是一种搜索的方式 回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本…...
(2)VTK C++开发示例 --- 绘制多面锥体
文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容👉内容导航 👈👉VTK开发 👈 1. 概述 VTK C开发示例程序; 使用C 和VTK绘制一个多面锥体。 环境说明系统ubuntu22.04、windows11cmake3.22、3.2…...
合同智能审核技术的发展与应用
一、背景与行业现状 合同审查作为企业合同管理的关键环节,其核心价值在于确保合同内容符合法律法规要求并契合企业内部政策。随着企业业务规模扩张带来的合同数量激增,传统人工审查方式在效率和成本方面的局限性日益凸显。这一现状为人工智能技术在合同…...
cryptozombies合约7
我们的合约几乎就要完成了!让我们加上一个事件. 事件 是合约和区块链通讯的一种机制。你的前端应用“监听”某些事件,并做出反应。 例子: // 这里建立事件 event IntegersAdded(uint x, uint y, uint result);function add(uint _x, uint _y) public…...
DeepSeek 接入 Word 完整教程
一、前期准备 1.1 注册并获取 API 密钥 访问 DeepSeek 平台: 打开浏览器,访问 DeepSeek 官方网站(或您使用的相应平台)。注册并登录您的账户。 创建 API 密钥: 在用户控制面板中,找到“API Keys”或“API…...
ARCGIS PRO DSK 利用两期地表DEM数据计算工程土方量
利用两期地表DEM数据计算工程土方量需要准许以下数据: 当前地图有3个图层,两个栅格图层和一个矢量图层 两个栅格图层:beforeDem为工程施工前的地表DEM模型 afterDem为工程施工后的地表DEM模型 一个矢量图层…...
大数据学习栈记——Redis安装及其使用
本文介绍NoSQL技术:Redis的安装及其使用。操作系统:Ubuntu24.04 Redis介绍 Redis是一个键值(key-value)存储系统,即键值对非关系型数据库,和Memcached类似,目前正在被越来越多的互联网公司采用…...
前端工程化之自动化构建
自动化构建 自动化构建的基本知识历史云构建 和 自动化构建 的区别:部署环境:构建:构建产物构建和打包的性能优化页面加载优化构建速度优化 DevOps原则反馈的技术实践 encode-bundlepackage.json解读src/cli-default.tssrc/cli-node.tssrc/cl…...
camx的xml解析
ls out/target/product/<product>/gen/STATIC_LIBRARIES/libcamxgenerated_intermediates/generated g_chromatix g_facedetection g_parser g_sensorg_chromatix/ tuning相关xml的解析codeg_facedetection/ 人脸检测相关xml的解析codeg_parser/ 主要的解析manager 流…...
虚幻引擎 Anim To Tex| RVT | RT
本文上篇分为4个部分:动画驱动材质,虚拟纹理,Rendertarget,以及其他杂项的地编ta干货整理。(其中RT部分基本为UOD重要截图摘录) 本文下篇为:skylight和directional light的区别,未完…...
计算机视觉与深度学习 | 钢筋捆数识别
===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== 钢筋捆数 1、初始结果2、处理效果不佳时的改进方法1、预处理增强2、后…...
关于PHP开源CMS系统ModStart的详细介绍及使用指南
关于PHP开源CMS系统ModStart的详细介绍及使用指南: 🔍 ModStart是什么? 基于Laravel框架开发的模块化CMS系统采用Apache 2.0 开源协议,完全免费可商用特别适合需要快速搭建企业级网站/管理系统的开发者 🚀 核心优势…...
VMware vCenter Server 安全漏洞升级方案一则
一、安全漏洞情况 根据VMware提供的安全建议(VMSA-024-0012),VMware vCenter Server可能经受以下漏洞的威胁: 漏洞一为VMware vCenter Server堆溢出漏洞(CVE-2024-37079,CVE-2024-37080)&…...
Linux服务之网络共享
目录 一.存储类型 二.NFS 2.1定义 2.2工作原理 2.3优势 2.4NFS工具 2.4.1exportfs 2.4.2showmount 2.5NFS相关软件及命令 2.6模拟实现NFS 准备工作(服务端和客户端都需要) 服务端位置 客户端配置 测试 补充:设置自动挂载 一.存…...
接口幂等性问题
幂等性问题出现在创建和更新数据时: 一、创建 1、在创建数据时,数据库方面,创建有效的唯一索引,用来数据兜底,并在程序中做异常捕获。 2、在插入数据时可以创建一个防重表做过滤,如果防重数据比较小又需…...
LeetCode每日一题4.14
1534. 统计好三元组 问题分析 遍历数组,满足好三元组定义,count1 思路 枚举i,j,k 代码 class Solution:def countGoodTriplets(self, arr: List[int], a: int, b: int, c: int) -> int:n len(arr)count 0for i in range…...
活动安排问题 之 前缀和与差分
文章目录 D. Robert Hood and Mrs Hood 考虑到一个活动开始时间和结束时间s,e,那么可以影响到的范围就是 s-d1,e,所以我们只需对这个每一个活动可以影响到的区域进行标记即可,当然为了降低时间复杂度,我们将使用前缀和与差分 t int(input()…...
HTTP 和 HTTPS 协议的区别及使用场景
在互联网的世界里,HTTP 和 HTTPS 是我们经常接触到的两种网络协议,它们在数据传输、安全性等方面存在诸多差异,适用的场景也各有不同。 一、HTTP 和 HTTPS 的基本概念 HTTP,即超文本传输协议(Hyper - Text Transfer Protocol),是一种用于分布式、协作式和超媒体信息…...
SAP 供应链:采购订单ME21N创建关键点
一、ME21N创建采购订单关键点 采购组织/采购组 字段:EKORG(采购组织)、EKGRP(采购组)关键点:采购组织必须与公司代码(Company Code)关联,采购组对应采购员职责范围示例&…...
重构无人机动力控制范式:Breeze 55A FOC 电调技术深度测评 ——全新Vfast 观测器如何突破效率与精度双重瓶颈
一、引言 在无人机动力系统中,电调(电子调速器)作为连接电池与电机的核心枢纽,其控制精度、效率及可靠性直接影响飞行性能。南昌长空科技的Breeze 55A FOC 电调凭借全新 Vfast 观测器技术与成熟的 FOC(矢量控制&#…...
LLM做逻辑推理题-哪一项圈出后不用找零
题目: 某天,两男两女走进一家自助餐厅,每人从机器上取下一许如下图所示的标价单。 50、95 45、90 40、85 35、80 30、75 25、70 20、65 15、60 10、55 (1)四人要同样的食品…...
第十章 json操作
第十章 json操作 文章目录 第十章 json操作一、Marshal 序列化二、Unmarshal 反序列化1 已知数据解析2 未知数据解析3 json测试 一、Marshal 序列化 package mainimport ("encoding/json""fmt" ) type Animal struct {Name string json:"name"…...
Python-Django集成yolov识别模型摄像头人数监控网页前后端分离
程序示例精选 Python-Django集成yolov识别模型摄像头人数监控网页前后端分离 如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助! 前言 这篇博客针对《Python-Django集成yolov识别模型摄像头人数监控网页前后端分离…...
「出海匠」借助CloudPilot AI实现AWS降本60%,支撑AI电商高速增长
🔎公司简介 「出海匠」(chuhaijiang.com)是「数绘星云」公司打造的社交内容电商服务平台,专注于为跨境生态参与者提供数据支持与智能化工作流。平台基于大数据与 AI 技术,帮助商家精准分析市场趋势、优化运营策略&…...