Vue开发实战-教程篇(下)

简介: 本文适合对vue开发过程有疑惑,以及对vue实际开发过程感兴趣的小伙伴阅读。

Axios


一、安装

npm install vue-axios --save


二、main.js引入

import axios from 'axios'
Vue.prototype.$axios = axios    //全局注册,使用方法为:this.$axios


三、使用

<script>
export default{
  data(){
    return{
      userId:666,
      token:'',
    }
  },
  created(){
    this.$axios({
      method:'post',
      url:'api',
      data:this.qs.stringify({    //这里是发送给后台的数据
            userId:this.userId,
            token:this.token,
      })
    }).then((response) =>{          //这里使用了ES6的语法
        console.log(response)       //请求成功返回的数据
    }).catch((error) =>
        console.log(error)       //请求失败返回的数据
    })
  }
}
</script>


四、请求拦截器

// http request 拦截器
instance.interceptors.request.use(
  config => {
    const token = sessionStorage.getItem('token')
    if (token ) { // 判断是否存在token,如果存在的话,则每个http header都加上token
      config.headers.authorization = token  //请求头加上token
    }
    return config
  },
  err => {
    return Promise.reject(err)
  })


五、响应拦截器

// http response 拦截器
instance.interceptors.response.use(
  response => {
    //拦截响应,做统一处理 
    if (response.data.code) {
      switch (response.data.code) {
        case 1002:
          store.state.isLogin = false
          router.replace({
            path: 'login',
            query: {
              redirect: router.currentRoute.fullPath
            }
          })
      }
    }
    return response
  },
  //接口错误状态处理,也就是说无响应时的处理
  error => {
    return Promise.reject(error.response.status) // 返回接口返回的错误信息
  })


六、在需要的页面导入就可以使用了

import instance from './axios'
/* 验证登陆 */
export function handleLogin (data) {
  return instance.post('/ds/user/login', data)
}


管理系统中使用的图标

项目中的图标需要集中管理起来,方便维护,减少一些图片重复引入

如果对安全没什么特殊要求:推荐使用iconfont

如果对安全有特别要求:把图标统一存放在内部服务


定制主题及动态切换主题

结合ElementUI使用

(Tips: 广东靓仔看到业界关于动态主题大约有6种方案,选了其中一种)

修改ElementUI提供的变量,先根据实际情况修改变量值


// 参考:https://element.eleme.cn/#/zh-CN/component/custom-theme
/* 改变主题色变量 */
$--color-primary: #545C64;
$--color-success: #27B6AF;
$--menu-background-color: #1D212A;
$--menu-item-font-color: #B3B8C3;
$--menu-item-hover-fill: #1F2D3D;
$--main-padding: 15px;
/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
// 通用的布局等样式
@import "../common";


common.scss片段:

// 自定义变量
$---menu--inline-background-color: #13161C !default;
$---index-header-height: 50px !default;
$---padding-common: 15px !default;
$---margin-common: 15px !default;
$---border-line-color: #E6E6E6 !default;
@import "~element-ui/packages/theme-chalk/src/index";
.el-menu-item.is-active {
  color: $--color-white;
  background-color: $--menu-item-hover-fill;
  font-weight: $--font-weight-primary;
}
// .............更多见GitHub源文件


main.js中引入

// 样式配置
import './assets/css/main.scss'


动态主题

定义好模板主题文件,这里列举了defaut、simple两个主题

image.png


main.scss主要内容:

// 实际样式引入
.theme-simple {
  @import "src/assets/themes/simple/index";
}
.theme-default {
  @import "src/assets/themes/default/index";
}


切换主题

改变body的样式名称即可,调用$changeTheme(theme)

const $themeList = [
  {
    id: 'theme-default',
    name: '默认主题'
  }, {
    id: 'theme-simple',
    name: '简单主题'
  }
]    
Vue.prototype.$changeTheme = function (theme = $themeList[0]) {
    const body = document.querySelector('body')
    $themeList.forEach(t => {
        body.classList.remove(t.id)
    })
    body.classList.add(theme.id)
    store.dispatch('Theme/changeTheme', theme) // 暂时保存到store里面
}


Tips: 图标在主题样式显示有点问题,使用font-face兼容下

//***********这块font定义是为了修复问题********************
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@font-face {
  font-family: 'element-icons';
  src: url('#{$--font-path}/element-icons.woff') format('woff'), url('#{$--font-path}/element-icons.ttf') format('truetype'); 
  font-weight: normal;
  font-display: auto;
  font-style: normal;
}


做好国际化

i18n


一、 使用国际化来更改咱们的项目语言

简单介绍下i18n如何用


1. 安装:

//使用yarn
yarn add vue-i18n 
//npm
npm i vue-i18n -S


2. 使用:

系统中使用它,必须通过 Vue.use() 明确地安装 vue-i18n:

src/i18n/index.js

//src/i18n/index.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
// 准备翻译的语言环境信息
const messages = {
  en: { 
    message: {
      hello: 'hello world'
    }
  },
  ja: {
    message: {
      hello: 'こんにちは、世界'
    }
  }
}
// 通过选项创建 VueI18n 实例
const i18n = new VueI18n({
  locale: 'ja', // 设置地区
  messages // 设置地区信息
})


3. 将i18n实例挂载在Vue的option中

import Vue from 'vue'
import i18n from "./src/i18n/index.js"
new Vue({
 i18n
})


4. 视图显示

<div id="app">
  <p>{{ $t("message.hello") }}</p>
</div>
------------------------------------
<!-- 展示效果如下 -->
<div id="app">
 <p>hello world</p>
</div>

在插值中使用$t函数就可以了


二、vue-cli项目中使用

1. 创建i18n文件结构

目录结构如下:

image.png


这里列举了两种语言分别是:en英文zh中文

en.js

export default {
  table: { // 假如用于翻译表格
    date: "Date",
    name: "Name",
    address: "Address"
  },
  menu: {}, // 假如项目中日后还有菜单
  tabs: {} // tab切换等
}


zh.js

export default {
  table: {
    date: "日期",
    name: "姓名",
    address: "地址"
  },
  menu: {},
  tabs: {}
}


config文件夹下面的index.js,代码如下(二者都可以):


乞丐版:

import en from './config/en'
import id from './config/id'
import ja from './config/ja'
import ae from './config/ae'
import am from './config/am'
import ca from './config/ca'
import al from './config/al'
.....


至尊版:

import Vue from "vue"
import VueI18n from "vue-i18n"
Vue.use(VueI18n)//注入到所有的子组件
//require.context(path,deep,regExp)
//有3个方法 分别是keys() 
// 至尊版
let langFileds = require.context('./config', false, /\.js$/)
let regExp = /\.\/([^\.\/]+)\.([^\.]+)$/ //正则用于匹配 ./en.js中的'en'
// regExp.exec('./en.js')
let messages = {} //声明一个数据模型,对应i18n中的message属性
langFileds.keys().forEach(key => {
    let prop = regExp.exec(key)[1] //正则匹配en|zh这样的值
    //messages[prop]相当于 messages['en'] = {table:{...}}
    messages[prop] = langFileds(key).default
})
console.log(messages);
console.log(langFileds('./en.js'));
let locale = localStorage.getItem('lang') || "zh" //从localstorag中获取
export default new VueI18n({
    locale,//指定语言字段
    messages//定义语言字段
})


2. 修改main.js

import Vue from 'vue'
import App from './App.vue'
import ElementUI from "element-ui" // 需要安装 element-ui
import 'element-ui/lib/theme-chalk/index.css';
Vue.config.productionTip = false
Vue.use(ElementUI)
import i18n from "./i18n" //
new Vue({
  render: h => h(App),
  i18n // 挂载
}).$mount('#app')


3. 具体使用demo

app.vue

<template>
  <div id="app">
    <template>
      <el-table :data="tableData"
                style="width: 100%">
        <el-table-column prop="date"
                         :label="$t('table.date')"
                         width="180">
        </el-table-column>
        <el-table-column prop="name"
                         :label="$t('table.name')"
                         width="180">
        </el-table-column>
        <el-table-column prop="address"
                         :label="$t('table.address')">
        </el-table-column>
      </el-table>
    </template>
    <el-button type="primary"
               @click="change('zh')">点击切换中文</el-button>
    <el-button type="primary"
               @click="change('en')">点击切换英文</el-button>
    <el-button type="primary"
  </div>
</template>
 <script>
  export default {
    mounted() {
      console.log(this.$i18n.t('table.date'));
    },
    methods: {
      change(lang) { //切换方法
        localStorage.setItem('lang', lang)
        window.location.reload() //localSotrage是不响应的,为了演示效果所以直接调用刷新
      }
    },
    data() {
      return {
        tableData: [{
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        }]
      }
    }
  }
  </script>
  <style>
  #app {
    width: 50%;
  }
</style>


构建打包发布


1. 打包配置如下:

build: {
    env: require('./prod.env'),
    index: path.resolve(__dirname, '../dist/index.html'),
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: './',
    productionSourceMap: true,
    // 默认情况下,Gzip 关闭了许多流行的静态主机,例如 
    // Surge 或 Netlify 已经为您压缩了所有静态资产。 
    // 在设置为 `true` 之前,请确保: 
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],
    // 运行带有额外参数的构建命令 
    // 构建完成后查看包分析器报告: 
    // `npm run build --report` 
    // 设置为 `true` 或 `false` 以始终打开或关闭它
    bundleAnalyzerReport: process.env.npm_config_report
  }


2. 一般部署,我们会结合Nginx一起使用

安装&启动

# 安装,安装完成后使用nginx -v检查,如果输出nginx的版本信息表明安装成功
sudo apt-get install nginx
# 启动
sudo service nginx start


3. 修改nginx配置

nginx的配置文件就在/etc/nginx文件夹

/etc/nginx/sites-available/default

image.png


nginx代理的根目录是/var/www/html

mkdir /www
echo 'Hello world' > /www/index.html

image.png


4. 同步到服务器

在git-bash或者powershell使用scp指令,如果是linux环境开发,还可以使用rsync指令:

scp -r dist/* root@117.78.4.26:/www
rsync -avr --delete-after dist/* root@117.78.4.26:/www


package.json脚本,方便,提高效率

"scripts": {
  "build": "vue-cli-service build",
  "push": "yarn build && scp -r dist/* root@117.78.4.26:/www"
},

当然啦,对于history、与hash模式,对应微调下即可~


做好组件的单元测试

Vue 的单文件组件使得为组件撰写隔离的单元测试这件事更加直接

组件的单元测试有很多好处:

  • 提供描述组件行为的文档
  • 节省手动测试的时间
  • 减少研发新特性时产生的 bug
  • 改进设计
  • 促进重构


一个简单的Demo:

<template>
  <div>
    <div class="message">
      {{ message }}
    </div>
    Enter your username: <input v-model="username">
    <div
      v-if="error"
      class="error"
    >
      Please enter a username with at least seven letters.
    </div>
  </div>
</template>
<script>
export default {
  name: 'Foo',
  data () {
    return {
      message: 'Welcome to the Vue.js cookbook',
      username: ''
    }
  },
  computed: {
    error () {
      return this.username.trim().length < 7
    }
  }
}
</script>


单元测试,代码如下:

import { shallowMount } from '@vue/test-utils'
import Foo from './Foo'
const factory = (values = {}) => {
  return shallowMount(Foo, {
    data () {
      return {
        ...values
      }
    }
  })
}
describe('Foo', () => {
  it('renders a welcome message', () => {
    const wrapper = factory()
    expect(wrapper.find('.message').text()).toEqual("Welcome to the Vue.js cookbook")
  })
  it('renders an error when username is less than 7 characters', () => {
    const wrapper = factory({ username: ''  })
    expect(wrapper.find('.error').exists()).toBeTruthy()
  })
  it('renders an error when username is whitespace', () => {
    const wrapper = factory({ username: ' '.repeat(7)  })
    expect(wrapper.find('.error').exists()).toBeTruthy()
  })
  it('does not render an error when username is 7 characters or more', () => {
    const wrapper = factory({ username: 'Lachlan'  })
    expect(wrapper.find('.error').exists()).toBeFalsy()
  })
})


Tips:  工厂函数将 values 对象合并到了 data 并返回了一个新的 wrapper 实例。好处有两个:

1. 不需要在每个测试中重复 const wrapper = shallowMount(Foo)

2.  当我们想为更复杂的组件在每个测试中伪造或存根一个方法或计算属性时,你只需要声明一次即可。


Vue Test Utils 及庞大的 JavaScript 生态系统提供了大量的工具促进 100% 的测试覆盖率。

推荐阅读:

https://v1.test-utils.vuejs.org/zh/guides/#%E8%B5%B7%E6%AD%A5


四、总结


   在我们阅读完官方文档后,我们一定会进行更深层次的学习,比如看下框架底层是如何运行的,以及源码的阅读。  


这里广东靓仔给下一些小建议:

  • 在看源码前,我们先去官方文档复习下框架设计理念、源码分层设计
  • 阅读下框架官方开发人员写的相关文章
  • 借助框架的调用栈来进行源码的阅读,通过这个执行流程,我们就完整的对源码进行了一个初步的了解
  • 接下来再对源码执行过程中涉及的所有函数逻辑梳理一遍
相关文章
|
6天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
6天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
5天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
5天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
JavaScript 测试技术 容器
Vue2+VueRouter2+webpack 构建项目
1). 安装Node环境和npm包管理工具 检测版本 node -v npm -v 图1.png 2). 安装vue-cli(vue脚手架) npm install -g vue-cli --registry=https://registry.
1050 0
|
6天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
6天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
7天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
7天前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
12天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发

相关实验场景

更多