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 相关文章推荐
推荐4个原生javascript常用的函数
Jan 12 Javascript
jQuery的bind()方法使用详解
Jul 15 Javascript
JS基于FileSystemObject创建一个指定路径的TXT文本文件
Aug 05 Javascript
原生JS实现匀速图片轮播动画
Oct 18 Javascript
巧用数组制作图片切换js代码
Nov 29 Javascript
Jquery鼠标放上去显示全名的实现方法
Feb 06 Javascript
footer定位页面底部(代码分享)
Mar 07 Javascript
详解从新建vue项目到引入组件Element的方法
Aug 29 Javascript
electron实现qq快捷登录的方法示例
Oct 22 Javascript
微信小程序canvas分享海报功能
Oct 31 Javascript
jQuery实现的移动端图片缩放功能组件示例
May 01 jQuery
JavaScript使用setTimeout实现倒计时效果
Feb 19 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:风雨欲来 路在何方?
2006/10/09 PHP
PHP callback函数使用方法和注意事项
2015/01/23 PHP
php生成图片缩略图功能示例
2017/02/22 PHP
ThinkPHP框架结合Ajax实现用户名校验功能示例
2019/07/03 PHP
Hutia 的 JS 代码集
2006/10/24 Javascript
基于jQuery实现左右div自适应高度完全相同的代码
2012/08/09 Javascript
Egret引擎开发指南之视觉编程
2014/09/03 Javascript
基于jQuery实现自动轮播旋转木马特效
2015/11/02 Javascript
谈谈我对JavaScript原型和闭包系列理解(随手笔记8)
2015/12/24 Javascript
BOM系列第二篇之定时器requestAnimationFrame
2016/08/17 Javascript
js的OOP继承实现(必看篇)
2017/02/18 Javascript
JS实现的Unicode编码转换操作示例
2017/04/28 Javascript
EasyUI Datebox 日期验证之开始日期小于结束时间
2017/05/19 Javascript
nodejs基于WS模块实现WebSocket聊天功能的方法
2018/01/12 NodeJs
基于jQuery ztree实现表格风格的树状结构
2018/08/31 jQuery
泛谈JS逻辑判断选择器 || &amp;&amp;
2019/05/24 Javascript
扫微信小程序码实现网站登陆实现解析
2019/08/20 Javascript
JavaScript实现秒杀时钟倒计时
2019/09/29 Javascript
15个简单的JS编码标准让你的代码更整洁(小结)
2020/07/16 Javascript
vue使用swiper实现左右滑动切换图片
2020/10/16 Javascript
[03:37]2014DOTA2国际邀请赛 主赛事第一日胜者组TOPPLAY
2014/07/19 DOTA
开源软件包和环境管理系统Anaconda的安装使用
2017/09/04 Python
Python迭代器定义与简单用法分析
2018/04/30 Python
使用Flask集成bootstrap的方法
2018/07/24 Python
对python pandas 画移动平均线的方法详解
2018/11/28 Python
python圣诞树编写实例详解
2020/02/13 Python
SQL Server 2000数据库的文件有哪些,分别进行描述
2013/03/30 面试题
学期自我评价
2014/01/27 职场文书
上海世博会口号
2014/06/19 职场文书
财务人员岗位职责
2015/02/03 职场文书
python基于OpenCV模板匹配识别图片中的数字
2021/03/31 Python
html+css合并表格边框的示例代码
2021/03/31 HTML / CSS
图解排序算法之希尔排序Java实现
2021/06/26 Java/Android
HTML5 新增内容和 API详解
2021/11/17 HTML / CSS
OpenCV项目实践之停车场车位实时检测
2022/04/11 Python
蓝牙耳机怎么连接电脑win11? Win11蓝牙耳机连接电脑的技巧
2023/01/09 数码科技