Vue-Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:javascript
vue + vue-router 主要是用来作 单页面应用(Single Page Application)。html
url改变后,立马发送请求,响应整个页面,有可能资源过多,传统的开发会让前端的页面出现“白屏”。前端
用户体验很差。vue
SPA:Single Page Applicationjava
锚点值改变后,不会马上发送请求,而是在某个合适的时机,发送ajax请求,局部改变页面中的数据。node
页面不马上跳转,用户体验好。react
前端路由:android
1.锚点值监视; 2.ajax获取动态的数据; 3.核心点是锚点值的改变;ajax
前端中的 vue/react/angular 都很适合作单页面应用。正则表达式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a href="#/login">登陆页面</a> <a href="#/register">注册页面</a> <div id="app"> </div> <script type="text/javascript"> // 获取div var oDiv = document.getElementById('app'); window.onhashchange = function () { console.log(location.hash); // 根据不一样的锚点值,对页面不一样的切换 switch (location.hash) { case '#/login': oDiv.innerHTML = '<h2>登陆页面</h2>'; break; case '#/register': oDiv.innerHTML = '<h2>注册页面</h2>'; break; default: // statements_def break; } } </script> </body> </html>
(1)window.onhashchange介绍
当一个窗口的 hash (URL中'#'后面的部分)改变时就会触发 onhashchange 事件。
onhashchange 事件在当前url的锚点部分(以'#'号为开始)发生改变时触发。
锚部分的实例:指定当前URL为http://www.example.com/test.htm#part2 - 这个 URL 中的锚部分为 #part2。
(2)onhashchange调用事件方法
(1)初始页面显示以下:
(2)点击登陆页面
(3)点击注册页面
(venv) MacBook-Pro:vue_study hqs$ cd 03-vue-router/ (venv) MacBook-Pro:03-vue-router hqs$ ls 01-前端路由实现原理.html vue.js (venv) MacBook-Pro:03-vue-router hqs$ npm init --yes Wrote to /Users/hqs/PycharmProjects/vue_study/03-vue-router/package.json: { "name": "03-vue-router", "version": "1.0.0", "description": "", "main": "vue.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } (venv) MacBook-Pro:03-vue-router hqs$ npm install vue-router -S 03-vue-router@1.0.0 /Users/hqs/PycharmProjects/vue_study/03-vue-router └── vue-router@3.0.1 npm WARN 03-vue-router@1.0.0 No description npm WARN 03-vue-router@1.0.0 No repository field.
查看项目文件目录:
<body> <div id="app"></div> <script type="text/javascript" src="vue.js"></script> <!--1.引入vue-router的对象--> <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script> <!--全局的VueRouter对象 vue-router还提供了两个全局的组件router-link / router-view--> <script type="text/javascript"> // 2.让Vue使用该VueRouter建立 Vue.use(VueRouter); var Login = { // 组件建立 template:` <div>登陆页面</div> ` }; var Register = { // 组件建立 template:` <div>注册页面</div> ` }; // 3.建立一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/login', // login路由 component:Login }, { path:'/register', component:Register } ] }); var App = { // App:入口组件 // router-link默认会被渲染为a标签,to属性默认会被渲染为href属性 // router-view是路由组件的出口 template:` <div> <router-link to="/login">登陆页面</router-link> <router-link to="/register">注册页面</router-link> <router-view></router-view> </div> ` }; new Vue({ // Vue实例化对象 el:'#app', components:{ App }, router, // router:router, 在key和value相同时能够只写一个 template:`<App/>` // 入口组件 }); </script> </body>
注意要点:
全局的VueRouter对象 vue-router 还提供了两个全局的组件router-link / router-view。
<router-link>
组件支持用户在具备路由功能的应用中 (点击) 导航。 经过 to
属性指定目标地址,默认渲染成带有正确连接的 <a>
标签,能够经过配置 tag
属性生成别的标签.。另外,当目标路由成功激活时,连接元素自动设置一个表示激活的 CSS 类名。
<router-view>
组件是一个 functional 组件,渲染路径匹配到的视图组件,是全部路由组件的出口。<router-view>
渲染的组件还能够内嵌本身的 <router-view>
,根据嵌套路径,渲染嵌套组件。
var App = { // router-link默认会被渲染为a标签 to属性默认会被渲染为href属性 // router-view是路由组件的出口 template:` <div> <router-link to="/login">登陆页面</router-link> <router-link to="/register">注册页面</router-link> <router-view></router-view> </div> ` };
这种问题就是由于本身建立的router对象没有被Vue实例化对象所使用:
new Vue({ // Vue实例化对象 el:'#app', components:{ App }, router, // router:router, 在key和value相同时能够只写一个 template:`<App/>` // 入口组件 });
1)点击前效果:
能够看到router-link默认会被渲染为a标签,to属性默认会被渲染为href属性。
2)点击后效果:
当你在页面访问login时,router-link对应着的路径是'/login',加载对应的component组件:Login,component组件找一个出口渲染出来:router-view。
有时候,经过一个名称来标识一个路由显得更方便一些,特别是在连接一个路由,或者是执行一些跳转的时候。你能够在建立 Router 实例的时候,在 routes
配置中给某个路由设置名称。
给当前的配置路由信息对象设置name属性。
对上面代码作以下修改:
var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/login', name:'login', // 设置路由名称 component:Login }, { path:'/register', name:'register', // 设置路由名称 component:Register } ] }); var App = { // 不使用to属性访问路由,改用动态命名路由绑定 // 要连接到一个命名路由,能够给 router-link 的 to 属性传一个对象: template:` <div> <router-link :to="{name:'login'}">登陆页面</router-link> <router-link :to="{name:'register'}">注册页面</router-link> <router-view></router-view> </div> ` };
<script type="text/javascript" src="vue.js"></script> <!--引入vue-router的对象--> <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
该模块默认会抛出一个VueRouter对象,另外还有两个全局的组件router-link和router-view。
// 若是使用模块化机制编程,导入Vue和VueRouter,要调用Vue.use(VueRouter) <script type="text/javascript"> // 让Vue使用该VueRouter建立 Vue.use(VueRouter); // 代码省略 </script>
// 3.建立一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/login', name:'login', // 设置路由名称 component:Login }, { path:'/register', name:'register', // 设置路由名称 component:Register } ] });
var App = { // 不使用to属性访问路由,改用动态命名路由绑定 // 要连接到一个命名路由,能够给 router-link 的 to 属性传一个对象: template:` <div> <router-link :to="{name:'login'}">登陆页面</router-link> <router-link :to="{name:'register'}">注册页面</router-link> <router-view></router-view> </div> ` }; new Vue({ el:'#app', components:{ App }, router, // router:router, 在key和value相同时能够只写一个 template:`<App/>` });
在vue-router路由中,传参方式通常分两种。以下所示:
(1)xxx.html#/user/1 params 动态路由参数 (2)xxx.html#/user?userId=2 query 查询
示例代码以下所示:
<body> <div id="app"></div> <script type="text/javascript" src="vue.js"></script> <!--1.引入vue-router的对象--> <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script> <!--全局的VueRouter对象 vue-router还提供了两个全局的组件router-link / router-view--> <script type="text/javascript"> // 路由范式 //(1)xxx.html#/user/1 params 动态路由参数 //(2)xxx.html#/user?userId=2 query 查询 // 2.让Vue使用该VueRouter建立 Vue.use(VueRouter); var UserParams = { template:` <div>我是用户1</div> `, created(){ // 接收参数 console.log(this.$route); // 其中包含params属性 console.log(this.$route.params.userId); // 输出:1 // 传参,发送ajax请求 console.log(this.$router); // VueRouter对象 } }; var UserQuery = { template:` <div>我是用户2</div> `, created(){ // 接收参数 console.log(this.$route); // 包含query属性,query: {userId: "2"} console.log(this.$route.query.userId); // 输出:2 // 传参,发送ajax请求 console.log(this.$router); // VueRouter对象 } }; // 3.建立一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/user/:userId', // params形式,动态路由参数,以冒号开头 name:'userp', // 设置路由名称 component:UserParams }, { path:'/user', name:'userq', // 设置路由名称 component:UserQuery } ] }); var App = { // 不使用to属性访问路由,改用动态命名路由绑定.要连接到一个命名路由,能够给 router-link 的 to 属性传一个对象 // 路由匹配,query是查询操做 template: ` <div> <router-link :to="{name:'userp', params:{userId:1}}">用户1</router-link> <router-link :to="{name:'userq', query:{userId:2}}">用户2</router-link> <router-view></router-view> </div> ` }; new Vue({ el:'#app', components:{ App }, router, // router:router, 在key和value相同时能够只写一个 template:`<App/>` }); </script> </body>
利用$route.query对象的Get方式传参,与http的get方式同样,会将参数暴露到地址栏。
var UserQuery = { template:` <div>我是用户2</div> `, created(){ // 接收参数 console.log(this.$route); // 包含query属性,query: {userId: "2"} console.log(this.$route.query.userId); // 输出:2 // 传参,发送ajax请求 console.log(this.$router); // VueRouter对象 } };
显示效果以下:
利用$route.params对象的Post方式传参,该方式具备必定限制,必须经过路径传参方式。
var UserParams = { template:` <div>我是用户1</div> `, created(){ // 接收参数 console.log(this.$route); // 其中包含params属性 console.log(this.$route.params.userId); // 输出:1 // 传参,发送ajax请求 console.log(this.$router); // VueRouter对象 } };
显示效果以下所示:
// vue-router.js文件558行到564行 Object.defineProperty(Vue.prototype, '$router', { get: function get () { return this._routerRoot._router } }); Object.defineProperty(Vue.prototype, '$route', { get: function get () { return this._routerRoot._route } });
至关于给vue实例化对象添加了两个属性$router(VueRouter)和$route(路由配置信息)。
// 3.建立一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/user/:userId', // params形式,动态路由参数,以冒号开头 name:'userp', // 设置路由名称 component:UserParams }, { path:'/user', name:'userq', // 设置路由名称 component:UserQuery } ] });
注意params形式,是配置动态路由参数,要以冒号开头。
var App = { // 不使用to属性访问路由,改用动态命名路由绑定.要连接到一个命名路由,能够给 router-link 的 to 属性传一个对象 template:` <div> <router-link :to="{name:'userp', params:{userId:1}}">用户1</router-link> <router-link :to="{name:'userq', query:{userId:2}}">用户2</router-link> <router-view></router-view> </div> ` };
访问效果以下所示:
除了使用 <router-link>
建立 a 标签来定义导航连接,咱们还能够借助 router 的实例方法,经过编写代码来实现。
对上例作以下修改,再也不使用声明式的<router-link :to='...'>,改成使用编程式:router.push(...)
var App = { // 不使用to属性访问路由,改用动态命名路由绑定.要连接到一个命名路由,能够给 router-link 的 to 属性传一个对象 template:` <div> <button @click="paramsHandler">用户1</button> <button @click="queryHandler">用户2</button> <router-view></router-view> </div> `, methods:{ paramsHandler(){ // 编程式导航 this.$router.push({ name: 'userp', params: { userId: 123 }}) }, queryHandler(){ this.$router.push({ name: 'userq', query: {userId: 3221} }) } } };
params访问显示效果:
query访问显示效果:
location, onComplete?, onAbort?
) 注意:在 Vue 实例内部,你能够经过 $router
访问路由实例。所以你能够调用 this.$router.push
。
想要导航到不一样的 URL,则使用 router.push
方法。这个方法会向 history 栈添加一个新的记录,因此,当用户点击浏览器后退按钮时,则回到以前的 URL。
当你点击 <router-link>
时,这个方法会在内部调用,因此说,点击 <router-link :to="...">
等同于调用 router.push(...)
。
该方法的参数能够是一个字符串路径,或者一个描述地址的对象。例如:
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: 123 }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
注意:若是提供了 path
,params
会被忽略,上述例子中的 query
并不属于这种状况。取而代之的是下面例子的作法,你须要提供路由的 name
或手写完整的带有参数的 path
:
const userId = 123 router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 这里的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user
一样的规则也适用于 router-link
组件的 to
属性。
在 2.2.0+,可选的在 router.push
或 router.replace
中提供 onComplete
和 onAbort
回调做为第二个和第三个参数。这些回调将会在导航成功完成 (在全部的异步钩子被解析以后) 或终止 (导航到相同的路由、或在当前导航完成以前导航到另外一个不一样的路由) 的时候进行相应的调用。
注意:若是目的地和当前路由相同,只有参数发生了改变 (好比从一个用户资料到另外一个 /users/1
-> /users/2
),你须要使用 beforeRouteUpdate
来响应这个变化 (好比抓取用户信息)
实际生活中的应用界面,一般由多层嵌套的组件组合而成。一样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件,例如:
/user/foo/profile /user/foo/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
借助 vue-router
,使用嵌套路由配置,就能够很简单地表达这种关系。
<body> <div id="app"></div> <script type="text/javascript" src="vue.js"></script> <!--1.引入vue-router的对象--> <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script> <!--全局的VueRouter对象 vue-router还提供了两个全局的组件router-link / router-view--> <script type="text/javascript"> // 嵌套路由: // 需求:进入首页后,点击音乐(/home/music) 电影(/home/movie) // 2.让Vue使用该VueRouter建立 Vue.use(VueRouter); var Home = { // 子路由出口 template:` <div> <br/> <router-link to="/home/music">音乐</router-link> <router-link to="/home/movie">电影</router-link> <router-view></router-view> </div> ` }; var Music = { template:` <div>我是音乐</div> ` }; var Movie = { template:` <div>我是电影</div> ` }; // 3.建立一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/', redirect:'home' // redirect:{name:'home'} // 命令路由的方式 }, { path:'/home', // params形式,动态路由参数,以冒号开头 name:'home', // 设置路由名称 component:Home, children:[ // 动态路由匹配表示你的子组件中的结构是不一样的 // 当访问/home组件时,Home组件的出口是不会渲染任何内容的, // 这是由于没有匹配到合适的子路由 { path:'', // 访问空字符串就表示访问/home了 component:Music // 默认加载孩子组件Music }, { path:'music', // 本身会默认去拼接斜杠 component:Music // 对应加载的组件 // children: // 能够继续配置三层路由 }, { path:'movie', // 本身会默认去拼接斜杠 component:Movie // 对应加载的组件 } ] }, ] }); var App = { // 路由出口 template:` <div> <router-link :to="{name:'home'}">首页</router-link> <router-view></router-view> </div> `, }; new Vue({ el:'#app', components:{ App }, router, // router:router, 在key和value相同时能够只写一个 template:`<App/>` }); </script> </body>
(1)以 /
开头的嵌套路径会被看成根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
(2)children
配置就是像 routes
配置同样的路由配置数组,因此呢,你能够嵌套多层路由。
这个警告的意思是:当父路由有子路由时,不容许子路由中有命名路由。所以对代码作以下调整
var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/', redirect:'home' // redirect:{name:'home'} // 命令路由的方式 }, { path:'/home', // params形式,动态路由参数,以冒号开头 // name:'home', // 设置路由名称 component:Home, children:[ // 动态路由匹配表示你的子组件中的结构是不一样的 // 当访问/home组件时,Home组件的出口是不会渲染任何内容的, // 这是由于没有匹配到合适的子路由 { path:'', // 访问空字符串就表示访问/home了 component:Music // 默认加载孩子组件Music }, { path:'music', // 本身会默认去拼接斜杠 component:Music // 对应加载的组件 // children: // 能够继续配置三层路由 }, { path:'movie', // 本身会默认去拼接斜杠 component:Movie // 对应加载的组件 } ] }, ] }); var App = { // 路由出口 template:` <div> <!--<router-link :to="{name:'home'}">首页</router-link>--> <router-link to="/home">首页</router-link> <router-view></router-view> </div> `, };
再次查看控制台,警报解除:
咱们常常须要把某种模式匹配到的全部路由,全都映射到同个组件。例如,咱们有一个 User
组件,对于全部 ID 各不相同的用户,都要使用这个组件来渲染。那么,咱们能够在 vue-router
的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果。
const User = { template: '<div>User</div>' } const router = new VueRouter({ routes: [ // 动态路径参数 以冒号开头 { path: '/user/:id', component: User } ] })
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<!--1.引入vue-router的对象-->
<script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
<!--全局的VueRouter对象 vue-router还提供了两个全局的组件router-link / router-view-->
<script type="text/javascript">
// 2.让Vue使用该VueRouter建立
Vue.use(VueRouter);
var Timeline = {
template:`
<div>
<router-link :to="{name:'comDesc', params:{id:'android'}}">Android</router-link>
<router-link :to="{name:'comDesc', params:{id:'frontend'}}">前端</router-link>
<router-view></router-view>
</div>
`
};
var Pins = {
template:`
<div>
我是沸点
</div>
`
};
// 共同的子组件
var ComDesc = {
data(){
return{
msg:''
}
},
template:`
<div>
我是{{msg}}
</div>
`,
created(){ // 生命周期方法
alert(1);
this.msg = '安卓';
}
};
// 3.建立一个路由对象
var router = new VueRouter({
// 配置路由对象
routes:[
// 动态路由参数以冒号开头
{
path:'/timeline',
component:Timeline,
children:[
{
path:"",
component:ComDesc // 访问Timeline时访问共同组件ComDesc
},
{
path:'/timeline/:id',
name:'comDesc',
component:ComDesc // 访问子动态路由时,也加载共同组件ComDesc
}
]
},
{
path:'/pins',
component:Pins
}
]
});
var App = {
// 路由出口
template:`
<div>
<router-link to="/timeline">首页</router-link>
<router-link to="/pins">沸点</router-link>
<router-view></router-view>
</div>
`,
};
new Vue({
el:'#app',
components:{
App
},
router, // router:router, 在key和value相同时能够只写一个
template:`<App/>`
});
</script>
</body>
var router = new VueRouter({ // 配置路由对象 routes:[ // 动态路由参数以冒号开头 { path:'/timeline', component:Timeline, children:[ { path:"", component:ComDesc // 访问Timeline时访问共同组件ComDesc }, { path:'/timeline/:id', name:'comDesc', component:ComDesc // 访问子动态路由时,也加载共同组件ComDesc } ] }, { path:'/pins', component:Pins } ] });
/timeline/android和/timeline/frontend都将映射相同的路由。
一个“路径参数”使用冒号 :
标记。当匹配到一个路由时,参数值会被设置到 this.$route.params
,能够在每一个组件内使用。
当使用路由参数时,例如从 /user/foo
导航到 /user/bar
,原来的组件实例会被复用。由于两个路由都渲染同个组件,比起销毁再建立,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
// 共同的子组件 var ComDesc = { data(){ return{ msg:'' } }, template:` <div> 我是{{msg}} </div> `, created(){ // 生命周期方法 alert(1); this.msg = '安卓'; } };
初始状态:
点击首页,显示alert:
点击确认后显示:
点击前端:
再点回安卓或首页,页面显示会调整,但都再也不显示alert。说明生命周期钩子再也不运行。
前面已经说到当使用路由参数时,例如从 /user/foo
导航到 /user/bar
,原来的组件实例会被复用。由于两个路由都渲染同个组件,比起销毁再建立,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
复用组件时,想对路由参数的变化做出响应的话,你能够简单地 watch (监测变化) $route
对象:
// 共同子组件 var ComDesc = { data(){ return{ msg:'' } }, template:` <div> 我是{{msg}} </div> `, created(){ // 生命周期方法 // alert(1); // this.msg = '安卓'; }, watch:{ '$route' (to, from) { // 对路由变化做出响应... console.log(to); console.log(from); } } };
var ComDesc = { data(){ return{ msg:'' } }, template:` <div> 我是{{msg}} </div> `, created(){ // 生命周期方法 // alert(1); // this.msg = 'android'; }, watch:{ '$route' (to, from) { // 对路由变化做出响应... console.log(to); console.log(from); // 直接渲染 this.msg = to.params.id; } } };
点击显示效果以下所示:
也能够看到组件没有再次被销毁或建立。
<keep-alive>
是Vue的内置组件,能在组件切换过程当中将状态保留在内存中(缓存),防止重复渲染DOM。
(1)Props:
(2)用法:
<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition>
类似,<keep-alive>
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出如今父组件链中。
当组件在 <keep-alive>
内被切换,它的 activated
和 deactivated
这两个生命周期钩子函数将会被对应执行。
主要用于保留组件状态或皮面从新渲染。
<script type="text/javascript"> // 2.让Vue使用该VueRouter建立 Vue.use(VueRouter); var Timeline = { template:` <div> 我是首页 </div> `, created(){ console.log('首页组件建立了'); }, mounted(){ console.log('首页组件DOM加载了'); }, destroyed(){ console.log('首页销毁了'); } }; var Pins = { template:` <div> <h3 @click="clickHandler">我是沸点</h3> </div> `, methods:{ clickHandler(e){ e.target.style.color = 'red'; } }, created(){ console.log('沸点组件建立了'); }, mounted(){ console.log('沸点组件DOM加载了'); }, destroyed(){ console.log('沸点销毁了'); }; // 3.建立一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ // 动态路由参数以冒号开头 { path:'/timeline', component:Timeline, }, { path:'/pins', name:'pins', component:Pins } ] }); var App = { // keep-alive组件保持缓存,把router-view渲染的出口缓存起来 template:` <div> <router-link to="/timeline">首页</router-link> <router-link to="/pins">沸点</router-link> <router-view></router-view> </div> `, }; new Vue({ el:'#app', components:{ App }, router, // router:router, 在key和value相同时能够只写一个 template:`<App/>` }); </script>
此时尚未使用keep-alive,切换页面时都会执行生命周期操做:
并且切换到沸点页面,点击“我是沸点”,能够将字体变红,可是切换到首页再切换沸点时,又变黑色了。也说明了从新进行了建立销毁。
注意:<keep-alive>
是用在其一个直属的子组件被开关的情形。若是你在其中有 v-for
则不会工做。若是有上述的多个条件性的子元素,<keep-alive>
要求同时只有一个子元素被渲染。
var App = { // keep-alive组件保持缓存,把router-view渲染的出口缓存起来 template:` <div> <router-link to="/timeline">首页</router-link> <router-link to="/pins">沸点</router-link> <keep-alive> <router-view></router-view> </keep-alive> </div> `, };
显示效果以下:
能够看到第一次点击会建立和加载,但并无销毁DOM,从首页切换到沸点,仍保持为红色。