脚手架、vue-router
1 Vue CLI
Command-Line Interface 命令行界面,可以帮助我们生成相关的依赖和代码。
如果想安装新版本,需要先卸载
npm uninstall vue-cli -g
npm install -g @vue/cli
脚手架官网:https://cli.vuejs.org/zh/
1.1 脚手架2的目录
build、config 用来做webpack配置
build指令:执行build文件下的 build.js, node为js提供了运行环境,node使用c++开发,v8引擎(js代码直接转2进制,不转成字节码)
config->useEslint改成false禁用js严格语法。
通过vue生成项目目录时 选择runtime+compiler还是runtime-only的区别:
runtimecompiler:常规方法,注册组件->绑定模板->挂载页面元素->显示
runtime-only:只有挂载,没有组件注册,搞了个render属性,这个属性执行一个函数。这里要结合一下vue的执行过程:我们写好的模板template->ast抽象语法数->编译成render函数->转为虚拟dom->真实dom
所以runtimonly模式就是跳过前两个步骤,直接render开始。runtimeonly比较快而且编译出来的代码较少,所以一般都选这个。
render:function(createElement){
return createElement('h2',{class:'box'},['hello world'])
}
createElement函数可以传入一个标签,他会创造这个标签并替换挂载元素.对象给标签属性,数组给标签内容。
除了传入这些东西外,这个createElement可以传入一个组件。
1.2 CLI3的使用
根目录下没有build和config的配置目录,增加了vueUi来进行配置。
vue create 项 目 名 称
上来会让你选择配置:按空格选中
这些配置你是放到package.json还是单独的配置文件中呢?
是否保存刚刚的预配置
生成的目录:
当前的main.js
import Vue from 'vue'
import App from './App.vue'
//构建信息展示
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app') //mount 跟el:'#app'挂载一样,内部执行的就是mount
cli3的配置都被隐藏起来了,可以通过vue ui里访问修改,安装依赖等,也可以创建自定义配置文件,注意文件名必须是vue.config.js。
2 vue-router
2.1 路由
路由就是通过互联网把信息传递给另一个地址的活动。
先来介绍一下路由器做了啥:
- 路由:决定数据包从来源到目的地的路径
- 转送:将输入端的数据传递到合适的输出端
数据包从一个公网地址(202.111.22.22这种)通过互联网发送给家里的路由器的公网地址,路由器拿到数据后下发给对应的内网ip地址(192.168.1.1)通过内网ip地址的路由映射表找到对应的计算机。
路由映射表大概是这样:[
内网ip1: 电脑mac地址1
内网ip2:电脑mac地址2
]
2.2 前端路由与后端路由
后端渲染
以前的网页都是后端渲染(jsp,php)。例如jsp当网页请求后,在后端把页面写好,jsp中除了html、css还有java代码,java代码可以读取数据库数据动态展示到页面上,当他给浏览器发回去的就是已经渲染好的页面了。
后端路由
那么这种url与页面的映射关系是由后端决定的就叫做后端路由。
前端渲染
由于后端渲染导致页面代码在维护、开发上的困难,开始了前后端分离阶段,页面利用ajax请求获得大量的数据,再通过js控制数据进行显示,这种就叫做前端渲染。
前端路由
SPA:单页面复应用。就是我一个url就包含了所有的网页功能。那么前端路由就是映射url和对应的组件的,需要使用什么组件,就请求对应组件的数据。这种前端复制url和资源管理的方式就叫做前端路由。
2.3 vue-router的使用
首先作为SPA页面,当url改变时我们不希望进行页面刷新。
- 通过修改loaction.hash锚点改变的url不会进行页面刷新,vue-router会自动监听
- history.pushState({},’’,‘home’) 同样
在安装了vue-router插件后,会多出来一个src/router文件夹,下面的index.js就是配置文件。Vue的所有插件都要通过vue.use(插件)来使用。
index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
//配置url和静态资源的映射关系
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
//2.创建vuerouter对象
const router = new VueRouter({
routes
})
//3.vue对象需要挂载,所以这里要导出
export default router
在main.js中挂载路由
import Vue from 'vue'
import App from './App.vue'
//如果这里导入的是个目录,他会自己找index.js去
import router from './router'
//构建信息展示
Vue.config.productionTip = false
new Vue({
router,//这里挂载vue-router
render: h => h(App)
}).$mount('#app')
那么接下来我们就要使用router了,我们需要明确vue-router作为前端路由的目的其实还是:通过url改变来改变页面
首先我们在App.vue中使用特殊组件 router-link,该标签类似于a标签(最终会被渲染为a标签),会修改当前的url。然后我们还需要写一个 router-view 他可以理解为一个占位符,当点击router-link时会把对应的组件渲染到router-view的位置上。
<template>
<div id="app">
<div id="nav">
<router-link to="/home">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
之后我们就要写目标为 / 和 /about 的路由映射,回到我们router/index.js中修改路由映射
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
然后写Home和About这俩被引入的组件。
其实这仨步骤应该倒过来做。。。
2.4 重定向
可以在routes数组中设置重定向:
const routes = [
{
path:'',
redirect:Home
}
...
这样当我们访问服务器url(localhost:8080/)时,就会直接重定向到Home组件对应的url上(localhost:8080/home)
2.5 使用history模式
默认router使用hash模式进行url改变,如果想使用history模式,在router/index.js中修改配置
使用history方法用户是可以点返回的
//2.创建vuerouter对象
const router = new VueRouter({
routes,
mode:'history'
})
2.6 router-link
router-link的tag属性可以把它渲染成其他标签
使用history方法用户是可以点浏览器返回的,给router-link增加replace属性,浏览器返回就点不了了(内部调用replaceState方法,不会形成历史记录)
<router-link to="/home" tag="button" replace=''>Home</router-link>
当我们点击这些router-link时,会自动添加一个class:router-link-exact-active router-link-active,这些class可以用来做样式修改等操作。如果想改变这个添加的class,使用属性activeClass=‘活跃属性名’,这样只能修改单个的router-link
<a href="/about" class="router-link-exact-active router-link-active">About</a>
如果那个修改全部,在index.js中修改router对象
const router = new VueRouter({
routes,
mode:'history',
linkActiveClass:'active'
})
如果我们不想通过router-link点击就实现它的功能要怎么做呢?
vue-router会给每一个组件都添加一个$router属性,利用它的push方法可以实现同样的跳转效果。
同样replace方法可以禁止浏览器返回
示例:
<template>
<div id="app">
<div id="nav">
<button @click="aboutClick">home</button>
</div>
<router-view/>
</div>
</template>
<script>
export default {
name:'App',
methods:{
aboutClick(){
//vue-router会给每一个组件都添加一个$router属性
this.$router.push('/about')
}
}
}
</script>
2.7 动态路由
很多时候我们的url后面还会加上一些信息(例如id)进入更具体的页面,这就要用到动态路由。
index.js 映射表:
{
path:'/user/:userId',//userId为标识符
component:User
}
通过v-bind绑定to属性
<router-link :to="'/user/'+userId">user</router-link>
User.vue如下:
<template>
<div>
<h2>用户界面</h2>
<h3>哈哈哈哈</h3>
<h4>userID {{userId}}</h4>
<h4>userID {{$route.params.userId}}</h4>
</div>
</template>
<script>
// 我们希望拿到对应url的用户信息
export default {
name:'User',
computed:{
userId(){
// $route获取当前处于活跃状态的url
//当前活跃的url下的参数下的userId属性
//通过这种方法就可以获取当前访问的用户id
return this.$route.params.userId
}
}
}
</script>
2.8 路由懒加载
所有的东西都在bundle.js中,所以请求如果全部资源都拿到就会很慢。CLI创建的项目自己就做了懒加载。
在bundle.js中它把src下的每一个js文件以数组元素的形式传入到一个__webpack_require__函数中并立即执行。
在CLI2里vue的dist路径下有多个js分别负责不同功能的文件导入。app.js负责业务逻辑,mainfest负责各种js的处理,vendor.js负责第三方插件的处理。
在index.js中
{
path: '/about',
name: 'About',
//这个就是懒加载,推荐把const about=() => import(/* webpackChunkName: "about" */ '../views/About.vue') 拿到外面去方便管理
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
2.9 路由嵌套
现在我们现在希望在当前路由的基础上访问子路径
例如我们在home的基础上设置两个子路径:home/news 和 home/message
首先创建两个vue文件,HomeNews和HomeMessage
修改index.js中的home路径的配置
const HomeNews=()=>import('../components/HomeNews')
const HomeMessage=()=>import('../components/HomeMessage')
const routes = [
{
path: '/home',
name: 'Home',
component: Home,
children: [
{
//注意这里不要加/
path:'news',
component:HomeNews
},
{
path:'message',
component:HomeMessage
}
]
},
...
那么子路径替换在什么位置呢?我们需要在Home.vue的template里去配置router-view
Home.vue 注意router-link要写上完整路径
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">信息</router-link>
<router-view/>
</div>
</template>
2.10 路由参数传递
-
params法
见动态路由中的$router和$route,这是参数传递的一种方式。
-
query 法
URL: 协议://主机(localhost):端口(8080,默认80可以不写)/路径?查询(query)
URL:scheme://host:port/path?query
<router-link :to="{path:'/profile',query:{name:'qu',age:18}}">profile</router-link>
Profile.vue
<template>
<div>
<h2>用户信息</h2>
<h3>{{$route.query.name}}</h3>
<h3>{{$route.query.age}}</h3>
</div>
</template>
2.11 $route和$router
在index.js中定义的router就是我们在所有组件中都可以使用过的this.$router
$route表示的就是index.js中routes里活跃的路由对象
那么这俩对象是怎么添加到所有组件上的呢?因为所有的组件都继承自Vue.prototype,如果你在原型上写属性,所有继承自该原型的对象都可以访问。vue-router在install的时候会创建这俩属性并赋值。
2.12 导航守卫
在一个SPA里如何改变网页的标题呢?我们可以利用生命周期函数created,但是这样不好维护。
我们可以利用导航守卫监听url的变化,index.js中使用如下函数
to就是我们要跳转到的那个url的路由信息。
//跳转前执行的钩子函数
router.beforeEach((to, from, next) => {
//从from跳到to
//使用matched[0]进行访问的话,在路由嵌套下的子路由里也能找到父路由的title
document.title = to.matched[0].meta.title;
next()
})
//跳转后执行的钩子函数(后置钩子)
router.afterEach
meta.title是在上面的对象中手动添加的
{
path: '/profile',
component: Profile,
meta: {
title: '用户信息'
}
}
除了这俩守卫还有路由独享守卫,可以在路由routes定义中执行,具体查官网。
2.13 keep-alive
keep-alive是vue内部的一个组件,可以是被包含的组件保留状态,避免重新创建和渲染。
<keep-alive>
<router-view/>
</keep-alive>
keep-alive带来了两个类似生命周期的函数 activated、deactivated,分别是路由活跃时触发,和路由不活跃时触发。
keep-alive属性:exclude排除组件,后面那个是组件的name,注意这里不要乱加空格
<keep-alive exclude="Profile,User,...">
<router-view/>
</keep-alive>
{
path: '/profile',
component: Profile,
meta: {
title: '用户信息'
}
}