記事の説明:この記事は、レガオのフロントエンドトレーニングキャンプのメモと経験です。何か問題がある場合は、指摘して教えていただければ幸いです。ありがとうございます。
ビュー-ルーター
1.ハッシュモードと履歴モード
ハッシュモードと履歴モードの違い
クライアント側ルーティングの実装がどのモードであっても、つまりルーティングパスが変更されても、サーバーにリクエストは送信されません。パスの変更を受信し、異なるアドレスに従って異なるコンテンツをレンダリングするのはjsです。サーバー側のコンテンツが必要な場合は、ajaxリクエストを送信して取得します。
症状の違い:
-
ハッシュモード
https://music.163.com/#/playlist?id=3102961863 -
履歴モード
https://music.163.com/playlist/3102961863、このモードを適切に使用するには、サーバー構成のサポートが必要です
原則の違い:
- ハッシュモードは、アンカーポイントとonhashchangeイベントに基づいており、アンカーポイントの値がルーティングアドレスとして使用されます。アドレスが変更されると、onhashchangeイベントがトリガーされます。onhashchangeイベントでは、現在のルーティングアドレスを記録します。パスに対応するコンポーネントを選択してから、レンダリングを再開します。つまり、ページに表示されるコンテンツは、パスに従って決定されます。
- 履歴モードはHTML5のHistoryAPIに基づいています。ie9より上のブラウザと互換性を持たせたい場合は、ハッシュモードを使用する必要があります。
1.
history.pushState()はIE10以降でのみサポートされます。history.push ()が呼び出されると、パスが変更され、サーバーに要求が行われます
。history.pushState()が呼び出されると、要求は行われません。サーバーに対しては、変更のみが行われます。ブラウザのパスバーにあるアドレスと、そのアドレスが履歴に記録されます。つまり、pushState()を使用してクライアント側のルーティングを実装できます。ただし、IE10以降で使用する必要があります。
2.history.replaceState()
履歴モードの使用
- シングルページアプリケーションでは、サーバーにhttp://www.testurl.com/loginのようなアドレスがない場合、ページが見つからないことが返されます。
- 静的リソースに加えて、サーバーはシングルページアプリケーションのindex.htmlを返す必要があります
nginxでの履歴
1.公式ウェブサイトでnginxの圧縮パッケージをダウンロードします
2.圧縮パッケージをハードディスクのルートディレクトリに解凍します:D:\ nginx-1.17.10、ディレクトリに中国語は表示されません
3.を開きますコマンドラインを開き、D:\ nginx-1.17.10に切り替えます。4。nginxを
起動します。
$ start nginx
5.nignxディレクトリにあるconf設定ファイルを開きます。6。
変更後に再起動します。
nginx -s reload
7.ローカルホストにアクセスするページに入ります。アクセスできます。これにより、vue-routerの履歴モードの問題が解決されます。
VueRouterの実装原理
VueRouterはフロントエンドルーターです。パスが切り替わると、ブラウザ側で現在のパスが判断され、現在のパスに対応するコンポーネントが読み込まれます。
ハッシュモード:
- URLの#の後のコンテンツがパスアドレスとして使用されます
- ハッシュ変更イベントをリッスンする
- 現在のルーティングアドレスに従って再レンダリングする対応するコンポーネントを見つけます
履歴モード
- history.pushState()メソッドを使用してブラウザのアドレスバーを変更し、アドレスバーを変更して現在のアドレスを閲覧履歴に記録すると、実際には指定されたパスにジャンプしません。つまり、ブラウザはサーバーリクエスト
- popstateイベントをリッスンし、ブラウザの履歴の変更を監視したり、変更されたアドレスをpopstate処理関数に記録したり、ブラウザの進むボタンまたは戻るボタンをクリックしたり、history.back()、forward()メソッドを呼び出したりできます。 popatateイベントをトリガーします
- アドレスが変更された場合は、現在のルーティングアドレスに基づいて対応するコンポーネントを見つけ、再レンダリングします
VueRouterクラス図:上から順に、クラス名、プロパティ、およびメソッドです。_は静的メソッドであり、+はパブリックメソッドです。
オプション:コンストラクターで渡されたオブジェクトを記録します。
routeMap:ルーティングアドレスとコンポーネント間の対応を記録し、ルーティングルールを
データに解析するために使用されるオブジェクト:routeMap内のオブジェクト。現在の属性は現在のルーティングアドレスを記録します。このデータを設定する目的は、レスポンシブオブジェクトを要求することです。ルーティングアドレスが変更された後、対応するコンポーネントを自動的に更新する必要があります。
プロジェクトディレクトリ:
約4つのステップがあります。最初に、公式のVue-routerの使用法(router / index.js)を確認してください。
main.js:
履歴モードでvuerouterを実装する、最初のステップ:
VueRouterフォルダーを作成し、次に新しいファイルindex.jsを作成し、VueRouterのインスタンスを作成します。Vueはuse(plugins)メソッドを使用してプラグインをVueに挿入します。 use methodプラグインVueRouterに挿入されたinstallメソッドが自動的に検出され、存在する場合はinstallメソッドが実行されます。VueRouter、一部のコンポーネントを含むVuexは、プラグインを介して実装されます。ブラウザ環境の場合、useメソッドはindex.jsで自動的に呼び出されます。ノード環境に基づいている場合は、手動で呼び出す必要があります。
_installメソッド:
beforeCreateフック操作をVueインスタンスに混在させる必要があります(Vueのライフサイクル中に呼び出されます)
// 定义一个全局变量
let _Vue = null
export default class VueRouter {
static install (Vue) {
// 1.判断当前插件是否已被安装
// 给install方法增加一个installed属性
if (VueRouter.install.installed) {
return
}
// 记录插件被安装
VueRouter.install.installed = true
// 2.把Vue构造函数记录到全局变量(我们要在VueRouter的实例方法中类使用Vue的构造函数,比如创建组件的时候使用Vue.component)
_Vue = Vue
// 混入,给所有的Vue实例设置选项
_Vue.mixin({
beforeCreate () {
if (this.$options.router) {
// 3.把创建Vue实例时候传入的router对象注入到所有Vue实例上
_Vue.prototype.$router = this.$options.router// 获取到Vue实例才能写
// 当插件注册完成的时候调用初始化方法
this.$options.router.init()
}
}
})
}
}
ステップ2:
VueRouterで初期化メソッドコンストラクターを作成する
// 初始化三个属性options,routeMap,data属性
constructor (options) {
// 记录传入的options
this.options = options
// 解析路由规则存储到routeMap里面
// router-view这个组件会根据当前地址寻找routeMap中对应的组件,渲染到浏览器中
this.routeMap = {
}
this.data = _Vue.observable({
// 存储当前的路由地址,当路由变化时要自动加载组件
// data要设置成响应式的对象,observable用来创建响应式对象,可以直接用着渲染函数或者计算属性里面
current: '/' // 当前的路由地址,默认为 /
})
}
ステップ3:
まず、コンストラクターで渡されたオプションのルーティングルール(ルート)をキーと値のペアに変換してrouteMapに格納するcreateRouteMap()メソッドを実装します。キーはルーティングアドレスであり、値は対応します。アドレスへ。sコンポーネント。アドレスが変更された場合、対応するコンポーネントを見つけてブラウザにレンダリングする必要があります。
createRouterMap () {
// 遍历所有路由规则,然后解析成键值对的形式存储的routeMap这个对象里面来
// 所有的路由规则都在options这个选项中,构造函数中传入了一个options,里面的某个属性叫routes
// routes 这个数组存储了所有的路由规则,在构造函数中我们把options这个选项存储到了当前VueRouter的options属性里面
// 当把routes 所有内容解析出来放到routerMap里面
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component
})
}
ステップ4:
initComponentsメソッドを実装します。このメソッドでは、router-linkおよびrouter-viewコンポーネントが作成されます。
app.vue:
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/video">Video</router-link>
</div>
<router-view/>
</div>
</template>
router-linkは、ハイパーリンクのアドレスである文字列型パラメーターtoを受け入れ、ホームのコンテンツをタグにレンダリングする必要があります
。router-viewコンポーネントはプレースホルダーと同等であり、router-viewコンポーネントは現在のルーティングアドレスに基づくルーティングアドレスは、ルータービューの場所にレンダリングされる現在のルーティングコンポーネントから取得されます
initComponents (Vue) {
// 传入Vue而不传入_Vue是为了减少该方法和外部的依赖
Vue.component('router-link', {
// 接受外部传入的参数
props: {
to: String
},
// 使用运行时版本的vue也就是不带编译器,此时不支持template选项
// 编译器的作用只是把template转换为render函数
// template:'<a :href = "to><slot></slot></a>'
// 在运行时版本中直接写render函数
render (h) {
return h('a', {
attrs: {
href: this.to
},
on: {
click: this.clickHandler// 给click注册clickHandler的点击事件
}
}, [this.$slots.default])
// 要创建的元素对应的选择器;设置a标签属性;通过代码(获取默认插槽:this.$slots.default)的形式获取slot内容放到数组当中来。
},
methods: {
clickHandler (e) {
// 传入事件参数e
// 调用pushstate方法改变浏览器的地址栏,不会向服务器发送请求
history.pushState({
}, '', this.to)
this.$router.data.current = this.to
e.preventDefault()// 阻止e的默认行为
}
}
// template: '<a :href = "to"><slot></slot></a>'
})
// 定义变量存储this,initcomponent中的this存储到self里面,self就是VueRouter的实例
const self = this
Vue.component('router-view', {
render (h) {
// 先找到当前路由的地址,再根据当前路由的地址去routermap对象中来找路由地址对应的组件
// 然后调用h函数帮我们把这个找到的组件转换成虚拟dom直接返回
// h函数还能直接把一个组件转换成虚拟dom
const component = self.routeMap[self.data.current]
return h(component)
}
})
}
initメソッドの作成には、createRouterMap()とinitComponents()、およびそれに続くinitEventが含まれます。
init () {
this.createRouterMap()
this.initComponents(_Vue)
this.initEvent()
}
ステップ5:
initEvent()を実装します。これは初期化メソッドであり、init()に配置する必要があります。
ブラウザの順方向および逆方向の方法をクリックした後、アドレスバーは変更されますが、ページのコンテンツは変更されます。つまり、アドレスに対応するコンポーネントはロードされません。ブラウザのアドレスが変更されたときにページの読み込みアドレスに対応するコンポーネントを更新する必要があります。このとき、ブラウザの履歴が変更されたときにトリガーされるpopstateイベントが必要です。
initEvent () {
// 注册popstate事件
window.addEventListener('popstate', () => {
// 把当前地址栏的地址取出来,把路径部分取出放到data.current里
this.data.current = window.location.pathname
})
}