天天看点

Vue.js电商后台项目笔记1

菜鸡新手向,这是我在学习vue.js项目时遇到的一些小问题,用来记录一下自己的学习经历,大家一起加油^_^

1.axios的导入

设置axios的默认地址,再将axios挂载到Vue上,然后就可以愉快的使用this.$http.+请求发送网络请求啦

// 导入axios
import axios from 'axios'
axios.defaults.baseURL = '' //输入地址
Vue.prototype.$http =axios
           

2.登录功能中的token

首先是了解localStorage和sessionStorage,两者唯一一点区别就是localStorage属于永久性储存,而sessionStorage属于当对话结束的时候,sessionStorage中的值才会被清空

而token之应该再打开该网站时生效,因此在登陆功能中,

window.sessionStorage.setItem(key,value)
           

通过以上的方法可以将token存储再sessionStorage中,传入两个参数,第一个时自定义名,可以设置为“token”,第二个就是实际中token的值。

3.路由守卫

一个简单的路由守卫结构 ,如下(未涉及到token的验证)

// 挂载路由导航守卫
router.beforeEach((to,from,next)=>{
  // to代表将要访问的路径
  // from代表从哪个路径跳转而来
  // next是一个函数,表示放行
  // next()放行   next('/login')表示强制跳转至目标'/login'路径
  if(to.path == '/login') return next()
  // 先看路径,如果路径是登录页面,那直接放行,如果不是,那就先获取token
  const tokenStr = window.sessionStorage.getItem('token')
  if(!tokenStr) return next('/login')
  next()
})
           

4.系统中的退出功能实现

通过清除sessionStorage中的token值实现退出,再指定跳转的页面即可

logout(){
   window.sessionStorage.clear();
   this.$router.push('/login')
}
           

5.在用户页面中,要使用需要授权的API,必须在请求头中使用Authorization字段提供token令牌才行,可以通过axios拦截器添加token验证,这样,每一次向浏览器发送需要授权的请求时,就会对进行token进行一次预验证

axios.interceptors.request.use(config => {
  config.headers.Authorization = window.sessionStorage.getItem("token")
  // 最后必须return(固定写法)
  return config;
});
           

再将axios拦截器设置在 axios挂载之前,完美

axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/'
axios.interceptors.request.use(config => {
  config.headers.Authorization = window.sessionStorage.getItem("token")
  // 最后必须return(固定写法)
  return config;
});
Vue.prototype.$http = axios
           

6.this.$router 和 this.$route(转载 本文链接:https://blog.csdn.net/u014395524/article/details/88194842)

this.$router 相当于一个全局的路由器对象,包含了很多属性和对象(比如 history 对象),任何页面都可以调用其 push(), replace(), go() 等方法。

this.$route 表示当前路由对象,每一个路由都会有一个 route 对象,是一个局部的对象,可以获取对应的 name, path, params, query 等属性。

关于 push() 方法:

想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。

当你点击 <router-link> 时,这个方法会在内部调用,所以说,点击 <router-link :to="..."> 等同于调用 router.push(...)。

push() 方法的调用:

//字符串
    this.$router.push('home')
 
    //对象
    this.$router.push({path:'home'})
 
    //命名的路由
    this.$router.push({name:'user', params:{userId: '123'}})
 
    //带查询参数,变成 /register?plan=private
    this.$router.push({path:'register', query:{plan:private}})
           

注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:

const userId = '123';
 
    this.$router.push({path:`/user/${userId}`});  //->/user/123
 
    this.$router.push({name:'user', params:{userId}});  //->/user/123
 
    //这里的 params 不生效
    this.$router.push({path:'/user', params:{userId}});  //->/user
           

params 传参,push 里面只能是 name:'xxx',不能是 path:'/xxx',因为 params 只能用 name 来引入路由,如果这里写成了 path ,接收参数页面会是 undefined。 

7.element-ui中清空表单

通过resetFields()完成

比如说想要在关闭dialog后清空位于dialog中的数据

<el-dialog title="添加用户" :visible.sync="addDialogVisible" width="50%" @close='addDialogClosed'>
      <!-- 内容主题区 -->
      <el-form
        :model="addForm"
        :rules="addFormrules"
        ref="addFormRef"
        label-width="70px"
      >
        <el-form-item label="用户名" prop="username">
          <el-input v-model="addForm.username"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input v-model="addForm.password" type="password"></el-input>
        </el-form-item>
      </el-form>
      <!-- 底部按钮区 -->
      <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addDialogVisible = false"
          >确 定</el-button
        >
      </span>
    </el-dialog>
           

 在dialog上添加一个@close='addDialogClosed',然后在methods中定义这个函数,用resetFields()方法清空即可

addDialogClosed(){
      this.$refs.addFormRef.resetFields()
    }
           

8.深拷贝Vue的运行依赖包lodash

在Vue依赖中下载lodash依赖包,然后再所需页面的script标签中导入

<script>
    import _ from 'lodash'
           

然后使用lodash中的cloneDeep()就可以实现深拷贝了!!👇

const form = _.cloneDeep(this.addForm)
           

这样就可以把addForm深拷贝一份form了

9.babel配置中移除console.log()

在项目开发阶段保留console.log()用作调试,而在发布阶段需要移除项目中所有的console.log(),这是需要在项目的babel.config.js文件中进行简单的配置

首先要安装babel-plugin-transform-remove-console的开发依赖包

Vue.js电商后台项目笔记1

 然后就可以在babel.config.js文件中进行相关的配置

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    [
      'component',
      {
        libraryName: 'element-ui',
        styleLibraryName: 'theme-chalk'
      }
    ],
    'transform-remove-console'
  ]
}
           

在plugins的数组中加入'transform-remove-console'就可以了,但是这样写有弊端,无论是开发还是发布阶段,项目中的console.log()都会被移除,我们只希望在发布阶段移除console.log(),那就需要做一个判断

在项目开发阶段时运行,mode值为development,而在项目发布阶段时,mode值为production,基于mode的值,就可以进行判断

Vue.js电商后台项目笔记1
Vue.js电商后台项目笔记1

 思路时先设置一个数组,然后再进行判断,最后把数组放到plugins中,搞定

const proPlugins = []
if(process.env.NODE_ENV === 'production'){
  proPlugins.push('transform-remove-console')
}

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    [
      'component',
      {
        libraryName: 'element-ui',
        styleLibraryName: 'theme-chalk'
      }
    ],
    ...proPlugins 
  ]
}
           

10.vue.config.js的配置

注意,这里相当于是定义了项目运行时的入口文件,如果是再开发(process.env.NODE_ENV === 'development')模式下,将入口文件main.js换成main-dev.js,如果是发布模式(process.env.NODE_ENV === 'production'),则将入口文件替换成main-prod.js,可以把src下的main.js复制一份再重命名(注意存放的路径不能出错,否则系统会找不到入口文件,直接报错!!!!)

module.exports = {
  lintOnSave: false,
  chainWebpack: config=>{
    config.when(process.env.NODE_ENV === 'production',config =>{
      config.entry('app').clear().add('./src/main-dev.js')
    })
    config.when(process.env.NODE_ENV === 'development', config=>{
      config.entry('app').clear().add('./src/main-prod.js')
    })
  }
}
           

11.通过externals加载外部CDN资源

在默认的情况下,通过import语法导入的第三方依赖包,最终会被打包合并到同一个文件中,从而导致打包合并后,单文件体积过大

Vue.js电商后台项目笔记1

为了解决上述问题,通过webpack的externals节点,在配置外部的CDN资源,凡是声明在externals中的第三方依赖包,都不会被打包,在vue.config.js文件中配置externals,这样在运行的时候,如果发现用import导入了一个包,👇,如axios,就不会把这个包(axios)合并到上述的文件中去,而是区window全局中寻找axios对象,然后直接来使用

module.exports = {
  lintOnSave: false,
  chainWebpack: config=>{
    // 发布模式
    config.when(process.env.NODE_ENV === 'production',config =>{
      config.entry('app').clear().add('./src/main-prod.js')

      config.set('externals',{
        vue:"Vue",
        'vue-router': 'VueRouter',
        axios: 'axios',
        lodash:'_',
        echarts : 'echarts',
        nprogress:'Nprogress',
        'vue-quill-editor':  'VueQuillEditor'
      })
    })
    // 开发模式
    config.when(process.env.NODE_ENV === 'development', config=>{
      config.entry('app').clear().add('./src/main-dev.js')
    })
  }
}
           

做完上面的配置,还需要在public/index.html文件的头部加上CDN资源的引用,例如我的项目中的CDN引用如下👇,可以用https://www.bootcdn.cn/,在这里面直接输入要引入的包名就可以找到了!!

<!DOCTYPE html>
<html >

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico" target="_blank" rel="external nofollow" >
  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
  <!-- nprogress样式表 -->
  <link href="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css" target="_blank" rel="external nofollow"  rel="stylesheet">
  <!-- 富文本编辑器css -->
  <link href="https://cdn.bootcdn.net/ajax/libs/quill/2.0.0-dev.3/quill.bubble.min.css" target="_blank" rel="external nofollow"  rel="stylesheet">
  <link href="https://cdn.bootcdn.net/ajax/libs/quill/2.0.0-dev.3/quill.core.min.css" target="_blank" rel="external nofollow"  rel="stylesheet">
  <link href="https://cdn.bootcdn.net/ajax/libs/quill/2.0.0-dev.3/quill.snow.min.css" target="_blank" rel="external nofollow"  rel="stylesheet">

  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
  <!-- 富文本编辑器js文件 -->
  <script src="https://cdn.bootcdn.net/ajax/libs/quill/2.0.0-dev.4/quill.min.js"></script>
</head>
           

12.首页内容定制

目标:希望在development下,在网页上显示dev-电商后台管理系统,而在production中显示的是 电商后台管理系统,并且在dev中不需要加载CDN,

思路:依旧是需要判断当前加载到底时development还是production,所以着手对号是在vue.config.js的配置中,在发布模ls式和开发模式中,找到一个插件,html,然后通过tap()修改插件中的链式操作,在tap中定义一个回调函数,args时插件中的参数项,在args中加上一个自定义属性,isProd,在发布模式中定义isProd为true,而在生产模式中定义isProd为false

module.exports = {
  lintOnSave: false,
  chainWebpack: config=>{
    // 发布模式
    config.when(process.env.NODE_ENV === 'production',config =>{
      config.entry('app').clear().add('./src/main-prod.js')

      config.plugin('html').tap(args=>{
        args[0].isProd = true
        return args
      })

      config.set('externals',{
        vue:"Vue",
        'vue-router': 'VueRouter',
        axios: 'axios',
        lodash:'_',
        echarts : 'echarts',
        nprogress:'Nprogress',
        'vue-quill-editor':  'VueQuillEditor'
      })
    })
    // 开发模式
    config.when(process.env.NODE_ENV === 'development', config=>{
      config.entry('app').clear().add('./src/main-dev.js')

      config.plugin('html').tap(args=>{
        args[0].isProd = false
        return args
      })
    })
  }
}
           

回到public中的index.html,htmlWebpackPlugin是参数名称,options中是参数项,isProd就是👆定义的参数,用三元运算符判断即可

<title>
    <%= htmlWebpackPlugin.options.isProd ? '': 'dev-'%>电商后台管理系统
  </title>
           

 然后就是希望在开发模式下不要加载CDN,可以用👇的代码把production中的CDN引入包裹起来,这样在加载开发模式时,页面就不会加载引入的CDN了

<% if(htmlWebpackPlugin.options.isProd){ %>
    //CDN
<% }%>
           

13.路由懒加载

在打包项目时,javascript的包会特别的大 ,影响页面的加载,需要把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样效果会更加高效

Vue.js电商后台项目笔记1

下载开发依赖包👆,然后在babel.config.js文件中👇

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    [
      'component',
      {
        libraryName: 'element-ui',
        styleLibraryName: 'theme-chalk'
      }
    ],
    // 发布产品时候的插件数组
    ...proPlugins,
    '@babel/plugin-syntax-dynamic-import'
  ]
}
           

然后就可以在路由中把不同的路径打包,如:👇,在webkpackChunkName中把login,home,welcome打包到一起加载,

const Login = () => import(/* webpackChunkName: 'login_home_welcome'*/ '../components/Login.vue')
const Home = () => import(/* webpackChunkName: 'login_home_welcome'*/ '../components/Home.vue')
const Welcome = () => import(/* webpackChunkName: 'login_home_welcome'*/ '../components/Welcome.vue')
           

14. 开启gzip配置

分为3步

    npm i compression -D //安装相应的包

    const compression = require("compression") //导入包

    app.use(compression()) //启动(要写在静态的前面)

const express = require("express")
const compression = require("compression")
const app = express()

// 
app.use(compression())//一定要写在静态之前
app.use(express.static('./dist'))

app.listen(80 , ()=>{
    console.log("server running at http://127.0.0.1")
})
           

继续阅读