Vue

Vue教育平台项目细节拆解

细节梳理,游刃有余

Posted by QQL on January 29, 2019

Vue项目感受

1.熟读官方文档

2.插件的全局应用,入口文件main.js

插件通常会为 Vue 添加全局功能。插件的范围没有限制——一般有下面几种:

1.添加全局方法或者属性,如: vue-custom-element

2.添加全局资源:指令/过滤器/过渡等,如 vue-touch

3.通过全局 mixin 方法添加一些组件选项,如: vue-router

4.添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。

5.一个库,提供自己的 API,同时提供上面提到的一个或多个功能,如 vue-router

最最常用4和5两点

通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成:
第五点实际操作
例一:

// 相当于调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)

new Vue({
  //... options
})

例二:

// elementUI 导入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 调用插件
Vue.use(ElementUI);

第四点实际操作

// 导入axios
import * as api from './restful/api'//导入restful/api全部export内容
Vue.prototype.$http = api;// Vue.prototype.$name=api给api起了别名为$http,可在全局调用,并且不会污染作用域

全局的css、js资源都在main.js入口文件中导入

import '../static/global/global.css'
import '../static/global/gt.js'

使用脚手架vue-cli创建项目引入文件可以忽略index.js/.vue文件的后缀名书写

原本 
./App.vue
./router/index.js

现在
import Vue from 'vue'
import App from './App'
import router from './router'

再main.js中实例化Vue对象

new Vue({
  el: '#app', //发生行为的目的地
  router, // 挂载路由插件vue-router,需要npm install vue-router --save
  store, // 挂载vuex一个store容器,需要npm install vuex --save
  components: { App },// 主组件,通常在其中实现单页面应用中,全局实现的功能页面
  template: '<App/>'// 模板
})

3.入口App.vue

入口App.vue通常当做组件挂载到main.js中,并作为起始页面在前端进行展示

<template>
  <div id="app">
    <!-- 导航区域 -->
    <BaseNavigationHeader />
  
    <router-view/>
  </div>
</template>

<script>
import BaseNavigationHeader from '@/components/Common/BaseNavigationHeader'
export default {
  name: 'App',// 为组件取名,在命名路由中会使用(例如::to="{name:'xxxx'}")
  components:{
    BaseNavigationHeader// 挂载子组件:导航栏
  }
}
</script>

<style scoped>
</style>

4.组件的解耦与路径拼接

在vue-cli脚手架中,为了让项目目录更加清晰,我们通常在src目录下(存放业务逻辑的目录),生成一个components目录专门存放各种组件
组件目录.png
如图所示,在components目录下创建一系列组件的文件夹,再在文件夹下创建组件.vue文件,遵循官方推荐项目结构编码规范

在项目中导入子组件时,vue-cli为我们优化了文件路径,用@代替了项目绝对路径…./proj_name/src

import Home from '@/components/Home/Home'
import Course from '@/components/Course/Course'
import LightCourse from '@/components/LightCourse/LightCourse'
import Micro from '@/components/Micro/Micro'
import CourseDetail from '@/components/Course/CourseDetail'
import Login from '@/components/Login/Login'
import Cart from '@/components/Cart/Cart'

5.路由系统vue-router的使用

为了让项目结构更加清晰,我们单独在项目src目录下创建router/index.js,用于解耦路由系统

import Vue from 'vue'
import Router from 'vue-router'
// @ 绝对路径 检索到 .....src/

// 如果我们Router当做全局模块使用 一定要Vue.use(Router)
// 以后在组件中  可以通过this.$router  获取Router实例化对象
// 路由信息对象 this.$routes
import Home from '@/components/Home/Home'
import Course from '@/components/Course/Course'
import LightCourse from '@/components/LightCourse/LightCourse'
import Micro from '@/components/Micro/Micro'
import CourseDetail from '@/components/Course/CourseDetail'
import Login from '@/components/Login/Login'
import Cart from '@/components/Cart/Cart'


Vue.use(Router)

// 配置路由规则
export default new Router({
   linkActiveClass:'is-active',//设置 链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 linkActiveClass 来全局配置
   mode: 'history',//改成history模式,URL中不会出现以#开头
  routes: [
    {
      path: '/',
      redirect:'/home' //访问'/'跳转到'/home'路由去
      // component: HelloWorld
    },
    {
    	path:"/home", // 路由
    	name:'Home', // 路由别名,需要与子组件export对象里name一致
    	component:Home // 路由组件
    },
    {
    	path:"/course",
    	name:'Course',
    	component:Course
    },
    {
    	path:"/home/light-course",
    	name:'LightCourse',
    	component:LightCourse
    },
    {
    	path:"/micro",
    	name:'Micro',
    	component:Micro
    },
    // 课程详情
    {
      //必须和Course.vue里的编程式路径跳转this.$router.push({})设置的name、param一致
      path:"/course/detail/web/:detailId",//编程式导航,动态UrlId :params对象里的key
      name:'course.detail',
      component:CourseDetail
    },
    {
      path:'/login',
      name:'Login',
      component:Login
    },
    // 购物车的页面
    {
      path:"/purchase/shopping_cart",
      name:'purchase.shop',
      component:Cart
    }
  ]
})

设置了路由后,在main.js中导入路由配置

import router from './router'

//在vue实例化对象中挂载router
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

6.ES6模块的import和export用法总结

ES6模块主要有两个功能:export和import

export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口

import用于在一个模块中加载另一个含有export接口的模块。

也就是说使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)。如下图(假设a和b文件在同一目录下)

// a.js

var sex="boy";
var echo=function(value){
  console.log(value)
}
export {sex,echo}  
//通过向大括号中添加sex,echo变量并且export输出,就可以将对应变量值以sex、echo变量标识符形式暴露给其他文件而被读取到
//不能写成export sex这样的方式,如果这样就相当于export "boy",外部文件就获取不到该文件的内部变量sex的值,因为没有对外输出变量接口,只是输出的字符串。
// b.js
通过import获取a.js文件的内部变量,{}括号内的变量来自于a.js文件export出的变量标识符。
import {sex,echo} from "./a.js" 
console.log(sex)   // boy
echo(sex) // boy

a.js文件也可以按如下export语法写,但不如上边直观,不太推荐。

// a.js
export var sex="boy";
export var echo=function(value){
  console.log(value)
}

//因为function echo(){}等价于 var echo=function(){}所以也可以写成
export function echo(value){
   console.log(value)
}

以上是export与module的基本用法,再进行拓展学习

前面的例子可以看出,b.js使用import命令的时候,用户需要知道a.js所暴露出的变量标识符,否则无法加载。可以使用export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名。

//a.js
var sex="boy";
export default sex(sex不能加大括号)
//原本直接export sex外部是无法识别的,加上default就可以了.但是一个文件内最多只能有一个export default。
其实此处相当于为sex变量值"boy"起了一个系统默认的变量名default,自然default只能有一个值,所以一个文件内不能有多个export default。
// b.js
本质上,a.js文件的export default输出一个叫做default的变量,然后系统允许你为它取任意名字。所以可以为import的模块起任何变量名,且不需要用大括号包含
import any from "./a.js"
import any12 from "./a.js" 
console.log(any,any12)   // boy,boy

7.导航栏技术核心

template中:
<div class="nav-center">
  <ul>
	<!-- v-for循环组件data中提供的数据,数据有id则key设置为单条数据id,无则设置为index-->
    <li v-for='(list,index) in headerList' :key='list.id'>
      <!-- 通过动态路由:to='{name:路由名称}'实现动态生成a标签-->
      <router-link :to='{name:list.name}'>
        
      </router-link>
    </li>
  </ul>
</div>

    <div class="nav-right " v-if='userInfo.access_token' @mouseenter='enterHandler' @mouseleave='leaveHandler'>
      <span class = 'el-dropdown-link'>学习中心</span>
      <span class="user"></span>
      <img :src="userInfo.avatar" alt="">
      <ul class="my_account" v-show='isShow'>
        <li>
          我的账户
          <i>></i>
        </li>
        <li>
          我的订单
          <i>></i>
        </li>
        <li>
          我的优惠券
          <i>></i>
        </li>
        <li>
          我的消息<span class="msg">(40)</span>
          <i>></i>
        </li>
        <li @click='shopCartInfo'>
          购物车<span class="count">()</span>
          <i>></i>
        </li>
        <li>
          退出
          <i>></i>
        </li>
      </ul>
    </div>
    <!-- </el-dropdown> -->
    <div class="nav-right" v-else>
      <span>登录</span>
      &nbsp;| &nbsp;
      <span>注册</span>
    </div>

script中:
export default{
	.....
	data() {
    return {
    //导航栏显示字段普遍不会变,通常由前端进行编写
      headerList: [
        { id: '1', name: 'Home', title: '首页' },
        { id: '2', name: 'Course', title: '免费课程' },
        { id: '3', name: 'LightCourse', title: '轻课' },
        { id: '4', name: 'Micro', title: '学位课程' }
      ],
      isShow: false// 控制下拉框的显示或隐藏

    }
  },
  //method中实现各种DOM操作的函数(鼠标悬浮、点击、input框。。。。),可在template中触发,也可以在vue生命周期中(比如created)中触发method
  method{
   shopCartInfo() {
     this.$router.push({// 实现编程式跳转vue-router在实例化时,抛出的属性$router,.push可实现路由跳转
       name: 'purchase.shop'// 跳转路由的别名
     })
   },
   enterHandler() {
     this.isShow = true;// 控制对data里的元素
   },
   leaveHandler() {
     this.isShow = false;
   }

 },
 computed: {// 计算属性,用来实现复杂的data数据操作
   userInfo() {
     console.log(this.$store.state.userInfo);
     return this.$store.state.userInfo;
   }
 }
  }
  .....
}