Vue学习 -- router路由

使用Vue开发项目,肯定对它的路由系统不会陌生。

直观感受

页面切换没有A标签那种明显的跳转以及新页面打开时的刷新等

概念

就是只有一个Web页面的应用,只加载单个HTML页面。在用户与应用程序交互时,动态更新该页面的Web应用程序。我们称之为SPA(单页应用程序)

区别

1、传统多页面程序:每次请求服务器返回的都是一个完整的页面

2、 单页应用程序:只有第一次会加载页面, 以后的每次请求, 仅仅是获取必要的数据.然后, 由页面中js解析获取的数据, 展示在页面中

优势

1 减少了请求体积,加快页面响应速度,降低了对服务器的压力

2 更好的用户体验,让用户在web app感受native app般的流畅

缺点

因为技术使用了ajax,导致页面不利于SEO,但是可以通过其他技术去规避

(SEO原则:搜索引擎的蜘蛛只识别href的一般超链接,而不识别JavaScript代码,遇到一般超链接就会爬进去,遇到JavaScript不会爬进去。即,搜索引擎抓不到AJAX动态加载的内容。)

History模式

HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;

新建vue-router-learn

自取的demo名称,具体demo地址

目录结构

vue-router-learn
├── README.md
├── .gitignore
├── node_modules
├── index.html
├── package.json
├── src
│ ├── main.js
│ └── pages
└── webpack.config.js

想知道这样的目录树如何自动生成,戳这里 安装tree

index.html

<body>
  <div id="app">
    {{ message }}
  </div>
  <!-- 注意这里的  script地址 -->
  <script src="/dist/build.js"></script>
</body>

大家可能好奇,刚才的根目录上也没有 dist 文件啊?不要着急往下看

package.json

{
  "name": "vue-router-learn",
  "private": true,
  "scripts": {
    "dev": "webpack-dev-server --inline --hot --open",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules",
    "predeploy": "npm run build"
  },
  "dependencies": {
    "vue": "^2.3.3"
  },
  "devDependencies": {
    "babel-core": "^6.0.0",
    "babel-loader": "^7.0.0",
    "babel-preset-env": "^1.6.1",
    "cross-env": "^4.0.0",
    "css-loader": "^0.28.1",
    "file-loader": "^0.11.1",
    "surge": "^0.19.0",
    "vue-loader": "^12.0.3",
    "vue-template-compiler": "^2.3.3",
    "webpack": "^2.5.1",
    "webpack-dev-server": "^2.4.5"
  }
}
//下载所有依赖
cnpm i 
//启动项目执行 
npm run dev

这里会用到webpack-dev-server ,其中有这么一句解释:

It uses webpack-dev-middleware under the hood, which provides fast in-memory access to the webpack assets.

main.js

import Vue from 'vue'

const routes = {
  '/': 'Home',
  '/about': 'About'
}
var app = new Vue({
    el: '#app',
    data: {
      message: 'Hello Vue!',
      currentRoute: window.location.pathname
    },
    computed: {
      ViewComponent () {

        const matchingView = routes[this.currentRoute];

        return matchingView
        ? require('./pages/' + matchingView + '.vue')
        : require('./pages/404.vue')

      }
    },
    render (h) { return h(this.ViewComponent) }
  })

其中如果不借助 webpack 直接使用import会报错:

Cannot use import statement outside a module

因为import 是es6的语法,而浏览器并不支持es6语法,当然你也可以在script 上添加type=“model”,或者频繁的使用script

<script src="./node_modules/vue/dist/vue.js" ></script>
 <script src="./src/main.js" ></script>

但显然不是我们想要的。所以还是借助webpack比较好

pages 存放页面

目前有三个页面 404、home、about

//404页
<template>
  <h1>这是404</h1>
</template>

//home 页
<template>
  <section>
    <nav>
      <a href="/">home页</a>
      <a href="/about">about页</a>
    </nav>
    <h1>这是home页</h1>
  </section>
</template>

//about 页
<template>
  <section>
    <nav>
      <a href="/">home页</a>
      <a href="/about">about页</a>
    </nav>

    <h1>这是about页</h1>
  </section>
</template>

效果

在这里插入图片描述
这是我们已经完成了一个简易的页面切换,当点击home/about 按钮时,URL会发生改变,然后通过window.location.pathname获得对应的router,最后通过render展示对应的组件,不太了解main.js写法的可以戳这里–看template部分

继续改造

但是他照样是通过A标签跳转的,并且每次都会刷新页面,所以咱们还需要借助 history.pushState API

router.js

export default {
  '/': 'Home',
  '/about': 'About'
}
//main.js   
//顶部加一行 import 引入 router文件
//保持不变
import routes from './router'

新建my-router-link

仿照router路由,新建一个my-router-link组件

<template>
  <a
    :href="to"
    :class="[{ active: isActive },'a']"
    @click="go"
  >
    <slot></slot>
  </a>
</template>

<script>
  import routes from '../router'

  export default {
    props: {
      to: {
        type:String,
        default:''
      }
    },
    computed: {
      isActive () {
        return this.to === this.$root.currentRoute
      }
    },
    methods: {
      go (event) {
        event.preventDefault()
        this.$root.currentRoute = this.to
        window.history.pushState(
          null,
          routes[this.to],
          this.to
        )
      }
    }
  }
</script>

<style scoped>
  .a{
    color: #333;
  }
  .active {
    color: cornflowerblue;
  }
</style>

引用my-router-link

// home页面

<template>
  <section class="about-wrap">
    <nav>
      <my-router-link to="/">home页</my-router-link>
      <my-router-link to="/about">about页</my-router-link>
    </nav>

    <h1>这是home页</h1>
  </section>
</template>

<script>
import MyRouterLink from '../components/my-router-link.vue'
export default {
  components:{
    MyRouterLink
  }
}
</script>

//about 页面同上
//只是把h1标签内容替换成 这是about页,方便切换页面时,有直观区别

效果

在这里插入图片描述
可惜csdn 没办法添加动效,所以看着和上一张效果图一样,其实是有区别大,我在这里先解释一下,感兴趣的小伙伴自己运行一下就知道了。

区别 这时点击tab按钮,URL改变,页面切换,但是不会像以前一样刷新了。

history.pushState

每执行一次都会增加一条历史记录,一共接收3个参数

history.pushState(data,title,url)

  • data:要设置的history.state的值,可以是任意类型的值,可根据此值进行判断执行想要的操作。

  • title:现在大多数浏览器不支持或者忽略这个参数,最好用null代替。

  • url:地址栏的值,若不需要可用空来代替。

history.replaceState(扩展知识)

replaceState()是用来修改当前的历史记录(history实体),而不是创建一个新的历史记录,所以当执行完history.replaceState()后,点击返回按钮照样会返回上一个一面。

当需要更新一个state对象或者当前history实体时,可以用replaceState()来实现。

popstate 监听

其实到这里添加路由已经差不多了,但是点击浏览器返回时,会发现页面没有反应,这里还需要对路由进行一下监听

改造后的main.js

//main.js
import Vue from 'vue'
import routes from './router'


var app = new Vue({
    el: '#app',
    data: {
      message: 'Hello Vue!',
      currentRoute: window.location.pathname
    },
    computed: {
      ViewComponent () {

        const matchingView = routes[this.currentRoute];

        return matchingView
        ? require('./pages/' + matchingView + '.vue')
        : require('./pages/404.vue')

      }
    },
    render (h) { return h(this.ViewComponent) }
  })

  window.addEventListener('popstate', () => {
  	//当点击浏览器返回按钮时,更新currentRoute,改变引用的pages页面
    app.currentRoute = window.location.pathname;
  })

history 刷新404问题

因为刷新是实实在在地去请求服务器的,history模式最终的路由都体现在url的pathname中,这部分是会传到服务器端的,因此需要服务端对每一个可能的path值都作相应的映射

// -e filename 如果 filename存在,则为真
location /{
    root   /**/**/文件目录;
    index  index.html index.htm;
    if (!-e $filename) {
        rewrite ^/(.*) /index.html last;
        break;
    }
}

hash模式

hash即URL中"#"字符后面的部分

1、使用浏览器访问网页时,如果网页URL中带有hash,页面就会定位到id(或name)与hash值一样的元素的位置;

2、hash还有另一个特点,它的改变不会导致页面重新加载;

3、hash值浏览器是不会随请求发送到服务器端的;

4、通过window.location.hash属性获取和设置hash值。

window.location.hash值的变化会直接反应到浏览器地址栏(#后面的部分会发生变化),同时,浏览器地址栏hash值的变化也会触发window.location.hash值的变化,从而触发onhashchange事件。

继续改造

hash和history 主要修改路由部分,其他文件都可以保持不变,因此咱们复用上边的项目,加以修改

修改my-router-link

//只需要修改 go 方法,将原有 History 部分注释掉
methods: {
  go (event) {
    event.preventDefault()
    this.$root.currentRoute = this.to
    
    //History 模式
    // window.history.pushState(
    //   null,
    //   routes[this.to],
    //   this.to
    // )

    //Hash模式
    window.location.hash =  this.to

  }
}

修改main.js

//注释掉History部分,添加hashchange 方法
 //History 模式
 // window.addEventListener('popstate', () => {
 //   app.currentRoute = window.location.pathname;

 // })

 //Hash模式
 window.addEventListener('hashchange',(e) =>{
   let pathname = e.newURL.split('/#')[1]
   app.currentRoute = pathname;
 },false);

1、当URL的片段标识符更改时,将触发hashchange事件(跟在#符号后面的URL部分,包括#符号)

2、hashchange事件触发时,事件对象会有hash改变前的URL(oldURL)和hash改变后的URL(newURL)两个属性

具体效果就不截图了,和上边实现的效果一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值