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 相关文章推荐
ExtJS 2.0实用简明教程 之Border区域布局
Apr 29 Javascript
基于jquery的跟随屏幕滚动代码
Jul 24 Javascript
jquery.post用法关于type设置问题补充
Jan 03 Javascript
javascript弹出页面回传值的方法
Jan 28 Javascript
javascript实现显示和隐藏div方法汇总
Aug 14 Javascript
纯JS焦点图特效实例(可一个页面多用)
Dec 07 Javascript
微信小程序 弹窗自定义实例代码
Mar 08 Javascript
详解Vue 普通对象数据更新与 file 对象数据更新
Apr 26 Javascript
node+koa2+mysql+bootstrap搭建一个前端论坛
May 06 Javascript
详解Vue项目引入CreateJS的方法(亲测可用)
May 30 Javascript
javascript设计模式 ? 外观模式原理与用法实例分析
Apr 15 Javascript
Vue自定义多选组件使用详解
Sep 08 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
php使用curl打开https网站的方法
2015/06/17 PHP
win10环境PHP 7 安装配置【教程】
2016/05/09 PHP
PHP convert_cyr_string()函数讲解
2019/02/13 PHP
jQuery 动态酷效果实现总结
2009/12/27 Javascript
Js setInterval与setTimeout(定时执行与循环执行)的代码(可以传入参数)
2010/06/11 Javascript
用JavaScript实现动画效果的方法
2013/07/20 Javascript
js判断页面中是否有指定控件的简单实例
2014/03/04 Javascript
使用Bootstrap Tabs选项卡Ajax加载数据实现
2016/12/23 Javascript
jquery,js简单实现类似Angular.js双向绑定
2017/01/13 Javascript
详谈AngularJs 控制器、数据绑定、作用域
2017/07/09 Javascript
微信小程序 上传头像的实例详解
2017/10/27 Javascript
vue scroll滚动判断的实现(是否滚动到底部、滚动方向、滚动节流、获取滚动区域dom元素)
2020/06/11 Javascript
解决vue项目获取dom元素宽高总是不准确问题
2020/07/29 Javascript
[26:40]DOTA2上海特级锦标赛A组资格赛#1 Secret VS MVP.Phx第一局
2016/02/25 DOTA
Python爬虫模拟登录带验证码网站
2016/01/22 Python
DataFrame中去除指定列为空的行方法
2018/04/08 Python
Python实现的直接插入排序算法示例
2018/04/29 Python
解决pycharm界面不能显示中文的问题
2018/05/23 Python
Python 爬虫之Beautiful Soup模块使用指南
2018/07/05 Python
解决Python plt.savefig 保存图片时一片空白的问题
2019/01/10 Python
HTML5 常见面试题之PC端和移动端区别介绍
2018/01/22 HTML / CSS
HTML5 Canvas 实现K线图的示例代码
2019/12/23 HTML / CSS
Alba Moda瑞士网上商店:独家意大利时尚女装销售
2016/11/28 全球购物
美国殿堂级滑板、冲浪、滑雪服装品牌:Volcom(钻石)
2017/04/20 全球购物
End Clothing美国站:英国男士潮牌商城
2018/04/20 全球购物
定义一结构体变量,用其表示点坐标,并输入两点坐标,求两点之间的距离
2015/08/17 面试题
什么是虚拟内存?虚拟内存有什么优势?
2012/02/19 面试题
《彩色世界》教学反思
2014/04/12 职场文书
国际贸易专业求职信
2014/06/04 职场文书
放飞理想演讲稿
2014/09/09 职场文书
落实八项规定专题民主生活会对照检查材料
2014/09/15 职场文书
承诺书范本大全
2015/05/04 职场文书
欠款起诉书范文
2015/05/19 职场文书
结婚司仪主持词
2015/06/29 职场文书
实习员工转正的评语汇总,以备不时之需
2019/12/17 职场文书
JavaScript实现队列结构过程
2021/12/06 Javascript