Vue项目中最新用到的一些实用小技巧


Posted in Javascript onNovember 06, 2018

写在前面

在最近的 Vue 项目中,为了完成需求使用了一些小技巧,做个笔记,或许也能帮到道友。

阅读重点

需求一:为路径配置别名

在开发过程中,我们经常需要引入各种文件,如图片、CSS、JS等,为了避免写很长的相对路径(../),我们可以为不同的目录配置一个别名。

找到 webpack.base.config.js 中的 resolve 配置项,在其 alias 中增加别名,如下:

创建一个 CSS 文件,随便写点样式:

.avatar
 display: flex;
 justify-content: center;
 align-items: center;

.avatar-img
 padding 20px
 border solid 1px #ccc
 border-radius 5px

接着,在我们需要引入的文件中就可以直接使用了:

<template>
 <div class="avatar">
 <img class="avatar-img" src="~img/avatar.png" alt="">
 </div>
</template>

<script>
 export default {
 name: "Home"
 }
</script>

<style scoped lang="stylus">
 @import "~css/avatar";
</style>

需要注意的是,如果不是通过 import 引入则需要在别名前加上 ~,效果如下:

Vue项目中最新用到的一些实用小技巧

需求二:要求实现在生产包中直接修改api地址

这个需求,怎么说呢,反正就是需求,就想办法实现吧。

假设有一个 apiConfig.js 文件,用于对 axios 做一些配置,如下:

import axios from 'axios';

axios.defaults.timeout = 10000;
axios.defaults.retry = 3;
axios.defaults.retryDelay = 2000;
axios.defaults.responseType = 'json';
axios.defaults.withCredentials = true;
axios.defaults.headers.post["Content-type"] = "application/json";

// Add a request interceptor
axios.interceptors.request.use(function (config) {
 // Do something before request is sent
 return config;
}, function (error) {
 // Do something with request error
 return Promise.reject(error);
});

// Add a response interceptor
axios.interceptors.response.use(function (response) {
 // Do something with response data
 return response;
}, function (error) {
 // Do something with response error
 return Promise.reject(error);
});

export default axios

在 static 文件夹中增加一个 config.json 文件,用于统一管理所有的 api 地址:

{
 "base": "/api",
 "static": "//static.com/api",
 "news": "//news.com.api"
}

打开 main.js,写入下列代码:

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import axios from 'js/apiConfig'; //import直接引入,不用添加~

Vue.config.productionTip = false;
Vue.use(ElementUI);

/* eslint-disable no-new */
let startApp = function () {
 let randomStamp = new Date().getTime();
 axios.get(`/static/config.json?t=${randomStamp}`).then((data) => {
 axios.defaults.baseURL = data.base; //设置一个默认的根路径
 Vue.prototype.$axios = axios;
 Vue.prototype.$apiURL = data; //将所有路径配置挂载到 Vue 原型上
 /* eslint-disable no-new */
 new Vue({
 el: '#app',
 router,
 components: {App},
 template: '<App/>'
 });
 })
};
startApp();

就是先用 axios 获取 api 文件,然后再初始化。

需求三:由后台根据用户权限值返回菜单

菜单是树形结构(PS:就算不是树形结构,你也得处理成树形结构),我这里使用的是 ElementUI ,参考了道友的这篇文章,实现如下:

新建一个 Menu.vue 文件,写入如下代码:

<script>
 export default {
 name: "MenuItem",
 props: {
 data: {
 type: Array
 },
 collapse: {
 type: Boolean
 }
 },
 methods: {
 //生成菜单项
 createMenuItem(data, createElement) {
 return data.map(item => {
  if (item.children && item.children.length) {
  return createElement('el-submenu', {props: {index: item.id.toString()}},
  [
  createElement('template', {slot: 'title'}, [
   createElement('i', {class: item.icon}),
   createElement('span', [item.title]),
   ]
  ),
  this.createMenuItem(item.children, createElement) //递归
  ]
  )
  } else {
  return createElement('el-menu-item', {props: {index: item.path}},
  [
  createElement('i', {class: item.icon}),
  createElement('span', {slot: 'title'}, [item.title]),
  ]
  )
  }
 })
 },
 //选中菜单
 onSelect(key, keyPath) {
 console.log(key, keyPath);
 }
 },
 render(createElement) {
 return createElement(
 'el-menu',
 {
  props: {
  backgroundColor: "#545c64",
  textColor: "#fff",
  activeTextColor: "#ffd04b",
  collapse: this.collapse,
  router:true
  },
  class:'el-menu-vertical-demo',
  on: {
  select: this.onSelect
  }
 },
 this.createMenuItem(this.data, createElement)
 )
 }
 }
</script>

<style scoped lang="stylus">
 .el-menu-vertical-demo:not(.el-menu--collapse) {
 width: 200px;
 min-height: 400px;
 }
</style>

这里主要用到两个东西,一个是 render 函数,一个是递归,如果不熟悉 render 函数的道友请点这里。可能有道友会问为什么不用模板,因为······做不到啊?,在 template 中只能有一个根元素,而 Vue 限制了不能对根元素使用 v-for;再者,通过在浏览器中查看代码可以知道,菜单就是 ul 加上 li,如果有了根元素会破坏标签结构(虽然不影响功能,但还是觉得不舒服?)。然后,在需要使用的地方:

<template>
 <el-container>
 <el-aside width="auto">
 <Menu :data="menu" :collapse="isCollapsed"></Menu>
 </el-aside>
 <el-container>
 <el-header>
 <el-button type="text" icon="el-icon-d-arrow-left"
   @click="isCollapsed=!isCollapsed"></el-button>
 <h3>MenuName</h3>
 <span>MeFelixWang</span>
 </el-header>
 <el-main>
 <router-view></router-view>
 </el-main>
 </el-container>
 </el-container>
</template>

<script>
 import Menu from '@/components/Menu';

 export default {
 name: 'App',
 data() {
 return {
 menu: [
  {
  title: '导航一',
  id: 1,
  path: '',
  icon: 'el-icon-search',
  children: [
  {
  title: '导航一杠一', id: 2, path: '', icon: '', children: [
   {title: '导航一杠一杠一', id: 4, path: '/test', icon: '', children: []},
   {
   title: '导航一杠一杠二', id: 5, path: '', icon: '', children: [
   {title: '导航一杠一杠二杠一', id: 6, path: '/6', icon: '', children: []},
   {title: '导航一杠一杠二杠二', id: 7, path: '/7', icon: '', children: []},
   ]
   },
  ]
  },
  {title: '导航一杠二', id: 3, path: '/3', icon: '', children: []}
  ]
  },
  {title: '导航二', id: 8, path: '/8', icon: 'el-icon-setting', children: []},
  {title: '导航三', id: 9, path: '/9', icon: 'el-icon-document', children: []},
  {
  title: '导航四', id: 10, path: '', icon: 'el-icon-date', children: [
  {title: '导航四杠一', id: 11, path: '/11', icon: '', children: []},
  {
  title: '导航四杠二', id: 12, path: '', icon: '', children: [
   {title: '导航四杠二杠一', id: 14, path: '/14', icon: '', children: []}
  ]
  },
  {title: '导航四杠三', id: 13, path: '/13', icon: '', children: []},
  ]
  },
 ],
 isCollapsed: false
 }
 },
 methods: {
 handleOpen(key, keyPath) {
 console.log(key, keyPath);
 },
 handleClose(key, keyPath) {
 console.log(key, keyPath);
 }
 },
 components: {
 Menu
 }
 }
</script>

<style lang="stylus">
 *
 margin 0
 padding 0

 html, body, .el-container, .el-aside
 height 100%

 .el-aside
 background-color rgb(84, 92, 100)

 .el-menu
 border-right solid 1px rgb(84, 92, 100)

 .el-header
 display flex
 justify-content space-between
 align-items center
 background-color aliceblue
 .el-button--text
 color: #606266;
 i
 font-weight bold
</style>

效果如下:

Vue项目中最新用到的一些实用小技巧

需求四:这个 Select 选项是树形结构,一定得是树形结构

树形结构就树形结构吧,不就是样式嘛,改改应该就可以了。

<template>
 <div>
 <el-select v-model="tree" placeholder="请选择活动区域">
 <el-option v-for="(item,index) in options" :key="index" :label="item.label" :value="item.id"
   :style="{paddingLeft:(item.level*10+20)+'px'}" :class="item.level?'is-sub':''"></el-option>
 </el-select>
 选择的是:{{tree}}
 </div>
</template>

<script>
 export default {
 name: "Home",
 data() {
 return {
 tree: '',
 options: [],
 originData: [
  {
  label: '这是根一', id: 1, children: [
  {label: '这是茎一一', id: 2, children: []},
  {label: '这是茎一二', id: 3, children: []},
  {
  label: '这是茎一三', id: 4, children: [
   {label: '这是叶一三一', id: 6, children: []},
   {label: '这是叶一三二', id: 7, children: []},
  ]
  },
  {label: '这是茎一四', id: 5, children: []},
  ]
  },
  {
  label: '这是根二', id: 8, children: [],
  },
  {
  label: '这是根三', id: 9, children: [
  {label: '这是茎三一', id: 10, children: []},
  {
  label: '这是茎三二', id: 11, children: [
   {label: '这是叶三二一', id: 12, children: []}
  ]
  },
  ],
  },
 ]
 }
 },
 created() {
 this.options = this.decomposeTree(this.originData, 0);
 },
 methods: {
 //分解树形结构
 decomposeTree(array, level) {
 let tmpArr = [];

 (function decompose(arr, lev) {
  for (let i = 0; i < arr.length; i++) {
  let tmpObj = {};
  let item = arr[i];
  item.level = lev;
  tmpObj = Object.assign({}, item);
  tmpArr.push(tmpObj);
  if (item.children) {
  decompose(item.children, lev + 1); //递归
  }
  delete tmpObj.children; //删掉其 children,避免数据过大(不删也可以,也许后面有用呢)
  }

 })(array, level);

 return tmpArr;
 }
 }
 }
</script>

<style scoped lang="stylus">
 .is-sub:before
 content '- '
</style>

因为 option 接收的是一个一维数组,所以通过递归展平树形结构,在展平的时候设置每项的层级,通过层级来设置缩进及前缀符号,效果如下:

Vue项目中最新用到的一些实用小技巧

之所以这样做,是因为是管理系统,简单有效,没必要因为这一个组件引个新的插件或者自己写一个(以后用得着的除外哈);也可以用 input 加上 tree 控件来模拟(PS:最终还是引入了一个插件,哈哈?)。

最后叨叨
本文是我最近用到的一些小技巧,如果道友们有更好的实现方法,欢迎在评论区留言讨论,文中错误也欢迎指出,共同学习

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
ajax 同步请求和异步请求的差异分析
Jul 04 Javascript
JS实现网站菜单拖拽移位效果的方法
Sep 24 Javascript
js实现新浪微博首页效果
Oct 16 Javascript
第四篇Bootstrap网格系统偏移列和嵌套列
Jun 21 Javascript
jQuery纵向导航菜单效果实现方法
Dec 19 Javascript
bootstrap输入框组使用方法
Feb 07 Javascript
JS实现图片预览的两种方式
Jun 27 Javascript
easyui datagrid 表格中操作栏 按钮图标不显示的解决方法
Jul 27 Javascript
vue-cli结合Element-ui基于cropper.js封装vue实现图片裁剪组件功能
Mar 01 Javascript
layui从数据库中获取复选框的值并默认选中方法
Aug 15 Javascript
Vue递归组件+Vuex开发树形组件Tree--递归组件的简单实现
Apr 01 Javascript
JavaScript中关于预编译、作用域链和闭包的理解
Mar 31 Javascript
详解Vue内部怎样处理props选项的多种写法
Nov 06 #Javascript
微信小程序实现选项卡效果
Nov 06 #Javascript
Vue props 单向数据流的实现
Nov 06 #Javascript
给localStorage设置一个过期时间的方法分享
Nov 06 #Javascript
移动端H5页面返回并刷新页面(BFcache)的方法
Nov 06 #Javascript
学习使用ExpressJS 4.0中的新Router的用法
Nov 06 #Javascript
vue项目上传Github预览的实现示例
Nov 06 #Javascript
You might like
WAR3重制版DOTA 5V5初体验
2020/04/09 DOTA
php生成txt文件标题及内容的方法
2014/01/16 PHP
PHP中把数据库查询结果输出为json格式简单实例
2015/04/09 PHP
PHP防止刷新重复提交页面的示例代码
2015/11/11 PHP
phalcon框架使用指南
2016/02/23 PHP
Zend Framework教程之Zend_Db_Table表关联实例详解
2016/03/23 PHP
thinkphp框架下实现登录、注册、找回密码功能
2016/04/06 PHP
微信公众号开发之文本消息自动回复php代码
2016/08/08 PHP
PHP手机号中间四位用星号*代替显示的实例
2017/06/02 PHP
js querySelector和getElementById通过id获取元素的区别
2012/04/20 Javascript
jQuery渐变发光导航菜单的实例代码
2013/03/27 Javascript
减少访问DOM的次数提升javascript性能
2014/02/24 Javascript
网站繁简切换的JS遇到页面卡死的解决方法
2014/03/12 Javascript
iframe跨域通信封装详解
2015/08/11 Javascript
js如何判断访问是来自搜索引擎(蜘蛛人)还是直接访问
2015/09/14 Javascript
JavaScript中Object.prototype.toString方法的原理
2016/02/24 Javascript
详解JS去重及字符串奇数位小写转大写
2016/12/29 Javascript
JavaScript对JSON数据进行排序和搜索
2017/07/24 Javascript
Vue-router结合transition实现app前进后退动画切换效果的实例
2017/10/11 Javascript
React Native中TabBarIOS的简单使用方法示例
2017/10/13 Javascript
解决Webpack 热部署检测不到文件变化的问题
2018/02/22 Javascript
Puppet的一些技巧
2018/09/17 Javascript
vue实现可视化可拖放的自定义表单的示例代码
2019/03/20 Javascript
Python图像灰度变换及图像数组操作
2016/01/27 Python
详解Python各大聊天系统的屏蔽脏话功能原理
2016/12/01 Python
Python列表list内建函数用法实例分析【insert、remove、index、pop等】
2017/07/24 Python
python定时检测无响应进程并重启的实例代码
2019/04/22 Python
python3.7将代码打包成exe程序并添加图标的方法
2019/10/11 Python
python实现获取单向链表倒数第k个结点的值示例
2019/10/24 Python
Under Armour安德玛中国官网:美国高端运动科技品牌
2018/03/09 全球购物
匡威英国官网:Converse英国
2018/12/02 全球购物
英智兴达软件测试笔试题
2016/10/12 面试题
企业项目策划书
2014/01/11 职场文书
2014年电厂个人工作总结
2014/11/27 职场文书
七个Python必备的GUI库
2021/04/27 Python
Python中的datetime包与time包包和模块详情
2022/02/28 Python