
github地址: >
初学vue问题记录
问题一、vue-router使用过程遇到的登录页空白问题
之前用vue-cli创建了一个vue项目,默认使用vue-router,目录结构中自带了router目录,里面有indexjs
但是当我又创建一个项目的时候默认没有使用vue-router时,后面我使用npm install vue-router安装了插件之后项目中没有自动创建router目录。查找资料显示说这种方式不会创建router目录,自己就把前面创建的项目的router目录及里面的文件拷贝过来使用。
使用的过程中,新建立的项目我自己单独写了一个Loginvue,想把这个登录页面作为首页,使用vue-router配置。我就修改了router目录的indexjs。如下:
mainjs中引入routerjs。如下:
到这里就是我找到的资料要配置登录页的,加上我不使用router-link,我就没有修改Appvue。我以为都配置完成了,就直接启动项目,发现页面空白。后来才发现Appvue中没有使用<router-view></router-view>。在Appvue加入<router-view></router-view>启动就成功显示登录页面了。
总结:使用vue-router,
1需要在router目录的indexjs维护好路由
2mainjs中引入router下文件
3Appvue中使用router-view
最后还发现了一个问题,用 >
前端路由是直接找到与地址匹配的一个组件或对象并将其渲染出来。改变浏览器地址而不向服务器发出请求有两种方式:
1 在地址中加入#以欺骗浏览器,地址的改变是由于正在进行页内导航
2 使用H5的windowhistory功能,使用URL的Hash来模拟一个完整的URL。
当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
目录结构
先来看看整体的目录结构
和流程相关的主要需要关注点的就是 components、history 目录以及 create-matcherjs、create-route-mapjs、indexjs、installjs。下面就从 basic 应用入口开始来分析 vue-router 的整个流程。
import Vue from 'vue'
import VueRouter from 'vue-router'
// 1 插件
// 安装 <router-view> and <router-link> 组件
// 且给当前应用下所有的组件都注入 $router and $route 对象
Vueuse(VueRouter)
// 2 定义各个路由下使用的组件,简称路由组件
const Home = { template: '<div>home</div>' }
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 3 创建 VueRouter 实例 router
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [
{ path: '/', component: Home },
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
})
// 4 创建 启动应用
// 一定要确认注入了 router
// 在 <router-view> 中将会渲染路由组件
new Vue({
router,
template: ` <div id="app">
<h1>Basic</h1>
<ul>
<li><router-link to="/">/</router-link></li>
<li><router-link to="/foo">/foo</router-link></li>
<li><router-link to="/bar">/bar</router-link></li>
<router-link tag="li" to="/bar">/bar</router-link>
</ul>
<router-view class="view"></router-view>
</div>
`
})$mount('#app')123456789101112131415161718192021222324252627282930313233343536373839404142
作为插件
上边代码中关键的第 1 步,利用 Vuejs 提供的插件机制 use(plugin) 来安装 VueRouter,而这个插件机制则会调用该 plugin 对象的 install 方法(当然如果该 plugin 没有该方法的话会把 plugin 自身作为函数来调用);下边来看下 vue-router 这个插件具体的实现部分。
VueRouter 对象是在 src/indexjs 中暴露出来的,这个对象有一个静态的 install 方法:
/ @flow /
// 导入 install 模块
import { install } from '/install'// import { inBrowser, supportsHistory } from '/util/dom'// export default class VueRouter {
// }
// 赋值 install
VueRouterinstall = install
// 自动使用插件if (inBrowser && windowVue) {
windowVueuse(VueRouter)
}123456789101112131415161718
可以看到这是一个 Vuejs 插件的经典写法,给插件对象增加 install 方法用来安装插件具体逻辑,同时在最后判断下如果是在浏览器环境且存在 windowVue 的话就会自动使用插件。
install 在这里是一个单独的模块,继续来看同级下的 src/installjs 的主要逻辑:
// router-view router-link 组件import View from '/components/view'import Link from '/components/link'// export 一个 Vue 引用export let _Vue// 安装函数export function install (Vue) {
if (installinstalled) return
installinstalled = true
// 赋值私有 Vue 引用
_Vue = Vue // 注入 $router $route
ObjectdefineProperty(Vueprototype, '$router', {
get () { return this$root_router }
}) ObjectdefineProperty(Vueprototype, '$route', {
get () { return this$root_route }
}) // beforeCreate mixin
Vuemixin({
beforeCreate () { // 判断是否有 router
if (this$optionsrouter) { // 赋值 _router
this_router = this$optionsrouter // 初始化 init
this_routerinit(this) // 定义响应式的 _route 对象
VueutildefineReactive(this, '_route', this_routerhistorycurrent)
}
}
}) // 注册组件
Vuecomponent('router-view', View)
Vuecomponent('router-link', Link)// }12345678910111213141516171819202122232425262728293031323334353637383940414243
这里就会有一些疑问了?
· 为啥要 export 一个 Vue 引用?
插件在打包的时候是肯定不希望把 vue 作为一个依赖包打进去的,但是呢又希望使用 Vue 对象本身的一些方法,此时就可以采用上边类似的做法,在 install 的时候把这个变量赋值 Vue ,这样就可以在其他地方使用 Vue 的一些方法而不必引入 vue 依赖包(前提是保证 install 后才会使用)。
· 通过给 Vueprototype 定义 $router、$route 属性就可以把他们注入到所有组件中吗?
在 Vuejs 中所有的组件都是被扩展的 Vue 实例,也就意味着所有的组件都可以访问到这个实例原型上定义的属性。
beforeCreate mixin 这个在后边创建 Vue 实例的时候再细说。
实例化 VueRouter
在入口文件中,首先要实例化一个 VueRouter ,然后将其传入 Vue 实例的 options 中。现在继续来看在 src/indexjs 中暴露出来的 VueRouter 类:
// import { createMatcher } from '/create-matcher'// export default class VueRouter {
//
constructor (options: RouterOptions = {}) {
thisapp = null
thisoptions = options
thisbeforeHooks = []
thisafterHooks = []
// 创建 match 匹配函数
thismatch = createMatcher(optionsroutes || [])
// 根据 mode 实例化具体的 History
let mode = optionsmode || 'hash'
thisfallback = mode === 'history' && !supportsHistory if (thisfallback) {
mode = 'hash'
} if (!inBrowser) {
mode = 'abstract'
}
thismode = mode switch (mode) {
case 'history':
thishistory = new HTML5History(this, optionsbase) break
case 'hash':
thishistory = new HashHistory(this, optionsbase, thisfallback) break
case 'abstract':
thishistory = new AbstractHistory(this) break
default:
assert(false, `invalid mode: ${mode}`)
}
}
// }123456789101112131415161718192021222324252627282930313233343536373839
里边包含了重要的一步:创建 match 匹配函数。
match 匹配函数
匹配函数是由 src/create-matcherjs 中的 createMatcher 创建的:
/ @flow /
import Regexp from 'path-to-regexp'// import { createRouteMap } from '/create-route-map'// export function createMatcher (routes: Array<RouteConfig>): Matcher {
// 创建路由 map
const { pathMap, nameMap } = createRouteMap(routes)
// 匹配函数 function match (
raw: RawLocation,
currentRoute: Route,
redirectedFrom: Location
): Route {
//
} function redirect (
record: RouteRecord,
location: Location
): Route {
//
} function alias (
record: RouteRecord,
location: Location,
matchAs: string
): Route {
//
} function _createRoute (
record: RouteRecord,
location: Location,
redirectedFrom: Location
): Route { if (record && recordredirect) { return redirect(record, redirectedFrom || location)
} if (record && recordmatchAs) { return alias(record, location, recordmatchAs)
} return createRoute(record, location, redirectedFrom)
}
// 返回 return match
}
// 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
具体逻辑后续再具体分析,现在只需要理解为根据传入的 routes 配置生成对应的路由 map,然后直接返回了 match 匹配函数。
继续来看 src/create-route-mapjs 中的 createRouteMap 函数:
/ @flow /import { assert, warn } from '/util/warn'import { cleanPath } from '/util/path'// 创建路由 mapexport function createRouteMap (routes: Array<RouteConfig>): {
pathMap: Dictionary<RouteRecord>,
nameMap: Dictionary<RouteRecord>
} { // path 路由 map
const pathMap: Dictionary<RouteRecord> = Objectcreate(null) // name 路由 map
const nameMap: Dictionary<RouteRecord> = Objectcreate(null) // 遍历路由配置对象 增加 路由记录
routesforEach(route => {
addRouteRecord(pathMap, nameMap, route)
}) return {
pathMap,
nameMap
}
}// 增加 路由记录 函数function addRouteRecord (
pathMap: Dictionary<RouteRecord>,
nameMap: Dictionary<RouteRecord>,
route: RouteConfig,
parent: RouteRecord,
matchAs: string
) {
// 获取 path 、name
const { path, name } = route
assert(path != null, `"path" is required in a route configuration`) // 路由记录 对象
const record: RouteRecord = {
path: normalizePath(path, parent),
components: routecomponents || { default: routecomponent },
instances: {},
name, parent,
matchAs,
redirect: routeredirect,
beforeEnter: routebeforeEnter,
meta: routemeta || {}
} // 嵌套子路由 则递归增加 记录
if (routechildren) {//
routechildrenforEach(child => {
addRouteRecord(pathMap, nameMap, child, record)
})
} // 处理别名 alias 逻辑 增加对应的 记录
if (routealias !== undefined) { if (ArrayisArray(routealias)) {
routealiasforEach(alias => {
addRouteRecord(pathMap, nameMap, { path: alias }, parent, recordpath)
})
} else {
addRouteRecord(pathMap, nameMap, { path: routealias }, parent, recordpath)
}
} // 更新 path map
pathMap[recordpath] = record // 更新 name map
if (name) { if (!nameMap[name]) {
nameMap[name] = record
} else {
warn(false, `Duplicate named routes definition: { name: "${name}", path: "${recordpath}" }`)
}
}
}function normalizePath (path: string, parent: RouteRecord): string {
path = pathreplace(/\/$/, '') if (path[0] === '/') return path if (parent == null) return path return cleanPath(`${parentpath}/${path}`)
}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
可以看出主要做的事情就是根据用户路由配置对象生成普通的根据 path 来对应的路由记录以及根据 name 来对应的路由记录的 map,方便后续匹配对应。
实例化 History
这也是很重要的一步,所有的 History 类都是在 src/history/ 目录下,现在呢不需要关心具体的每种 History 的具体实现上差异,只需要知道他们都是继承自 src/history/basejs 中的 History 类的:
/ @flow /// import { inBrowser } from '/util/dom'import { runQueue } from '/util/async'import { START, isSameRoute } from '/util/route'// 这里从之前分析过的 installjs 中 export _Vueimport { _Vue } from '/install'export class History {//
constructor (router: VueRouter, base: string) { thisrouter = router thisbase = normalizeBase(base) // start with a route object that stands for "nowhere"
thiscurrent = START thispending = null
}// }// 得到 base 值function normalizeBase (base: string): string { if (!base) { if (inBrowser) { // respect <base> tag
const baseEl = documentquerySelector('base') base = baseEl baseElgetAttribute('href') : '/'
} else { base = '/'
}
} // make sure there's the starting slash
if (basecharAt(0) !== '/') { base = '/' + base
在Web端Vue项目开发过程中,跨域问题是不可避免的;在我参与的Vue项目中,使用服务器代理的解决方案;针对不同的环境(开发环境/生产环境),采用了不同的服务器代理方案;
服务器代理的原理大概是这样:
代理服务器和访问源(请求端)是同源的,但和被访问服务器(资源端)是不同源的,但服务器之间的访问不受浏览器同源策略的影响(即不必担心是否有跨域问题),那么我们即可请求到同源服务器上的从被访问服务器上的获取到的请求资源了 ;
这样配置完成后,我们发起的每次>
vue中调用接口传输对象使用this$>
两种传参方式是不同的
get:
getInfo(){
consolelog(thispage)
this$>
以上就是关于Vue-awesome-swiper使用教程全部的内容,包括:Vue-awesome-swiper使用教程、vue项目中,解决开发与线上 请求接口不同的问题、vue-router使用过程遇到的问题等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)