单页面开发案例

1. vue cli 创建一个项目

我们会用到 vue-router

在 views 中创建组件 ,Center.vue、Cinermas.vue、Detail.vue、Films.vue、Login.vue、Order.vue、Search.vue(分别是我的,影院,详情,电影,登录,搜索,订单)。

这只是一个大概框架。

 再创建 films 文件,因为 在 电影页面中包含两个子组件,一个是正在热映 hotplaying.vue 组件,一个是预告电影 Comingsoon.vue.

当点击“我的” 展示用户信息。点击 “ 订单” 展示订单购票信息。点击 “ 影院” 展示附近的影院列表。

点击 “电影” 展示 最近正在热映的电影和预告电影,点击 ”搜索“ 搜索电影。当用户还未登录时,点击 “我的” 会跳转到“登录” 组件。

在 根组件 App.vue 中 显示三个菜单,点击一个菜单,该菜单高亮,进行组件之间的切换。v-slot 传回一个对象,navigate,表示点击的哪一个,isActive 就为 true ,class 值就为 myactive ,否则为 空。(class 用来设置高亮样式。) 详细内容可以见 https:// router.vuejs.org 路由官方文档。

<template>
  <div>
    <header>Welcome to Exciting Cinema</header>
    <ul>
      <router-link to="/films" custom v-slot="{navigate,isActive}">
      <li @click="navigate" :class="isActive?'myactive':''">
        电影--{{isActive}}
      </li>
      </router-link>
      <router-link to="/cinermas" custom v-slot="{navigate,isActive}">
      <li @click="navigate" :class="isActive?'myactive':''">
        影院--{{isActive}}
      </li>
      </router-link>
      <router-link to="/center" custom v-slot="{navigate,isActive}">
      <li @click="navigate" :class="isActive?'myactive':''">
        我的--{{isActive}}
      </li>
      </router-link>
    </ul>
    <!-- 路由容器 相当于插槽 -->
    <!-- router.vuejs.org 路由官方文档 -->
    <router-view></router-view>
  </div>
</template>

在 router 文件下 index.js 打开 注册并且引入路由

import Vue from 'vue'
import VueRouter from 'vue-router'
import Films from '@/views/Films'
import Cinermas from '@/views/Cinermas'
import Login from '@/views/Login'
import Hotplaying from '@/views/films/Hotplaying'
import Comingsoon from '@/views/films/Comingsoon'
import Search from '@/views/Search'
import Detail from '@/views/Detail'

Vue.use(VueRouter) // 注册路由插件
// 配置表
const routes = [
  {
    path: '/films',
    component: Films,
    // 二级路由(嵌套路由)
    children: [
      {
        path: '/films/hotplaying',
        component: Hotplaying
      },
      {
        path: '/films/comingsoon',
        component: Comingsoon
      },
      {
        path: '/films',
        redirect: '/films/hotplaying'
      }
    ]
  },
  {
    name: 'mydetil', // 命名路由
    path: '/detail/:myid', // 动态二级路由
    component: Detail
  },
  {
    path: '/cinermas',
    component: Cinermas
  },
  {
    path: '/cinermas/search',
    component: Search
  },
  {
    path: '/order',
    // 路由懒加载的方式,当需要这个组件出现了这个路径之后再加载 js 文件
    component: () => import('@/views/Order'),
    meta: {
      isMyrequired: true
    }
  },
  {
    path: '/login',
    component: Login
  },
  {
    path: '/center',
    component: () => import('@/views/Center'),
    meta: {
      isMyrequired: true
    }
  },
  {
    // 路由重定向  * 通配符匹配所有
    path: '*',
    redirect: '/films'
  }
]

const router = new VueRouter({
  mode: 'history', // 地址就没有 # 号了
  routes
})


router.beforeEach((to, from, next) => {
  console.log(to.fullPath)
  console.log(to)
  if (to.meta.isMyrequired) {
    // 判断本地存储中是否有 token 字段
    if (localStorage.getItem('token')) {
      next()
    } else {
      next({
        path: '/login',
        query: { myredirect: to.fullPath }
      }) // 重定向到 login 页面 , 并记录从哪儿来的,以备登录成功后再跳转回去。
    }
  } else {
    next()
  }
})
export default router

当用户在电影页面时。访客可以点击正在热映和预告电影。这里使用了嵌套路由,也可说是二级路由。因为访客不离开电影页面,只是页面内的两个组件切换。

  {
    path: '/films',
    component: Films,
    // 二级路由(嵌套路由)
    children: [
      {
        path: '/films/hotplaying',
        component: Hotplaying
      },
      {
        path: '/films/comingsoon',
        component: Comingsoon
      },
      {
        path: '/films',
        redirect: '/films/hotplaying'
      }
    ]
  },

最后一个路由 是始终保持电影页面默认显示 正在热映 组件 采用了重定向。

 用了重定向的地方还有这里,当访客在地址栏后面输入无效内容时都会默认跳转到 这个电影界面。

  {
    // 路由重定向  * 通配符匹配所有
    path: '*',
    redirect: '/films'
  }

当访客点击某一个 正在热映的电影时,需要加载这个电影的详情,这里使用动态路由。每一个电影用不通的id 标识。

 {
    name: 'mydetil', // 命名路由
    path: '/detail/:myid', // 动态二级路由
    component: Detail
  },

当未登录的用户点击“我的”或者查看订单时需要对其跳转进行拦截至登录页 Login.vue。登陆后才能跳转。这里采用的时全局拦截格式如下。

// 全局拦截
/*
router.beforeEach((to,from,next)=>{
  console.log(to)
  if(某几个需要授权的路由){
    if(授权通过){
      next()
    }else{
      next('/login') // 重定向到 login 页面
    }
  }else{
    next()
  }
})
*/

同时我们希望 能够记住用户在跳转登录前的页面,用户登录以后再跳转回来页面。

 

这里我们模拟用 token 字段来验证用户有无登录

  if (to.meta.isMyrequired) {
    // 判断本地存储中是否有 token 字段
    if (localStorage.getItem('token')) {
      next()

在需要拦截的 路径我们加了 meta 用来标记

  {
    path: '/center',
    component: () => import('@/views/Center'),
    meta: {
      isMyrequired: true
    }

这是路由懒加载的引入方式,因为当组件很多时,提高首页加载的速度,访客点击了其他的内容再去加载相应的 js 文件。

component: () => import('@/views/Center')

接下来来到 login.vue 

<template>
    <div>
        登录页面
        <button @click="handlogin()">登录</button>
    </div>
</template>
<script>
export default {
  methods: {
    handlogin () {
      setTimeout(() => {
        localStorage.setItem('token', '后端返回的 token 字段')
        // this.$router.back() // 返回
        // 1. 获取 query 字段
        console.log(this.$route.query.myredirect)
        // 2. 跳转到跳转之前的界面。
        this.$router.push(this.$route.query.myredirect)
      }, 2000)
    }
  }
}
</script>

 表示跳转到登录页面之前我是在 这个路径下 的页面。query 是我们上面拦截路由时所传的一个对象。

films.vue 这里用的声明式导航的另一种写法。因为导航栏不多可以手写。

<template>
    <div>
        <div class="lun">轮播</div>
        <ul>
            <router-link to="/films/hotplaying" tag="li" active-class="play_class">正在热映</router-link>
            <router-link to="/films/comingsoon" tag="li" active-class="play_class">即将上映</router-link>
        </ul>
        <router-view></router-view>
    </div>
</template>

detail.vue 当点击正在热映列表电影的时候就会显示页面创建完成。获得id和路径 .页面创建完成了

<template>
    <div>
        detail
    </div>
</template>
<script>

export default {
  created () {
    console.log('created', this.$route)
  },
  mounted () {
    console.log('mounted', this.$route.params.myid)
  }
}
</script>

 

hotplaing.vue 制造一个一一些假数据。这里介绍了点击跳转的三种方式。最后我们用了通过命名路由跳转方式。

<template>
    <div>
        hotplaying
        <ul>
            <li v-for="items in datalist" :key="items" @click="handetail(items)">{{items}}</li>
        </ul>
    </div>
</template>
<script>
export default {
  data () {
    return {
      datalist: ['1111', '2222', '3333']
    }
  },
  methods: {
    handetail (id) {
      // 编程式导航
      //   location.href = '#/detail'
      // 通过路劲跳转
      // this.$router.push(`/detail/${id}`)
      // 通过命名路由跳转
      this.$router.push({
        name: 'mydetil',
        params: {
          myid: id
        }
      })
    }
  }
}
</script>

因为要考虑不同设备大小的兼容性,这里使用 rem 等比例缩放。

在index.html 文件中设置等比例缩放,这里 750 *16 都是可以更改的。不过 px to rem 默认是16 ,如果更改也需要同步更改 px to rem 配置。

<script>
      // font-size 计算
      document.documentElement.style.fontSize=document.documentElement.clientWidth/750*16+'px'
    </script>

以及 px to rem 小工具来帮助我们实现 px 到 rem 的自动转换,px to rem 默认的是 16px

未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值