使用 Vue-cli 创建完项目,还需要进行一些配置才能进入开发模式,如果有老大当然是老大来做这些,但是万一这是落到你头上,可不懵逼了,简单的我总结下我配置的流程。
一、初始化样式
在 Jquery 的网页时代我们写项目的时候,为了去除 HTML 默认标签的影响,最常用的是雅虎的 reset.css 当然你也会参考别人自己写的。目前比较全的CSS重设(reset)方法总结
转眼到了 Vue 横行的 MVVM 时代。
Vue 项目的 reset.css或common.css
引入这个东西主要是解决两个问题:
- 隐藏浏览器的侧边滚动条,避免对布局的影响。
- 去除 HTML 标签的默认样式。
就算您不看下面的代码,在写项目的时候,也得把下面代码用到你的项目中。一般讲引用的位置有两个可以选择的地方:
- 第一个地方:main.js 文件(推荐)
import '../public/css/reset.css';
- 第二个地方在 App.vue 中引用,同时记住我们在引入的时候去掉 scoped
针对上面的样式文件做几点解释:
body, div, span, header, footer, nav, section, aside, article, ul, dl, dt, dd, li, a, p, h1, h2, h3, h4,h5, h6, i, b, textarea, button, input, select, figure, figcaption {
padding: 0;
margin: 0;
list-style: none;
font-style: normal;
text-decoration: none;
border: none;
font-family: "Microsoft Yahei",sans-serif;
-webkit-tap-highlight-color:transparent;
-webkit-font-smoothing: antialiased;
&:focus {
outline: none;
}
}
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
::-webkit-scrollbar
{
width: 0px;
height: 0px;
background-color: #F5F5F5;
}
/*定义滚动条轨道 内阴影+圆角*/
::-webkit-scrollbar-track
{
-webkit-box-shadow: inset 0 0 1px rgba(0,0,0,0);
border-radius: 10px;
background-color: #F5F5F5;
}
/*定义滑块 内阴影+圆角*/
::-webkit-scrollbar-thumb
{
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #555;
}
input[type="button"], input[type="submit"], input[type="search"], input[type="reset"] {
-webkit-appearance: none;
}
textarea { -webkit-appearance: none;}
html,body{
height: 100%;
width: 100%;
// background-color: #F5F5F5;
}
.fillcontain{
height: 100%;
width: 100%;
}
.clear:after{
content: '';
display: block;
clear: both;
}
.clear{
zoom:1;
}
.back_img{
background-repeat: no-repeat;
background-size: 100% 100%;
}
.margin{
margin: 0 auto;
}
.left{
float: left;
}
.right{
float: right;
}
.hide{
display: none;
}
.show{
display: block;
}
.ellipsis{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.multiellipsis3{
overflow : hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
-
-webkit-tap-highlight-color:transparent;
这个属性只用于 iOS (iPhone和iPad)。当你点击一个链接或者通过 Javascript 定义的可点击元素的时候,它就会出现一个半透明的灰色背景。把 -webkit-tap-highlight-color 设置为透明,重设它。 -
-webkit-font-smoothing: antialiased;
-webkit-font-smoothing 控制的字体渲染只对MacOS的Webkit有效。具体参考这个博客:CSS 中 -webkit-font-smoothing: antialiased 反而让字体更难看了? -
outline: none;
可以在 pc 端为 a 标签定义这个样式的目的是为了取消ie浏览器下点击a标签时出现的虚线和取消chrome下默认的文本框聚焦样式。
-
::-webkit-scrollbar
页面溢出的滚动条
这个千万记住,一定一定要加上,不然你在布局的时候,就尴尬了。我主要遇见两个问题:
- 页面过宽会跳动,去看看这个页面出现滚动条的时候没有跳动demo感受下导航跳动问题。
- 第二个就是页面导航条也是 body 的一部分,如果去掉滚动条的时候,你页面恰好平铺整个页面,但是滚动条出现可能导致盒子剩余宽度太窄,真个布局盒子掉了下来,在或者滚动条压住了内容。
这个滚动条这把我给折腾的够呛,那就多说几句,不重新写篇关于这个的文章了。还有个问题就是水平居中布局与滚动条跳动的千年难题这个问题也挺不好的。待解决的问题是:
当前web届,绝大多数的页面间布局都是水平居中布局,主体定个宽度,然后
margin: 0 auto
的节奏~然而,这种> > 布局有一个存在一个影响用户体验的隐患。应该都知道,现代浏览器滚动条默认是overflow:auto类型的,也就是如> 果尺寸不足一屏,没有滚动条;超出,出现滚动条。于是,问题来了:
- 信息流页面,新出现的页面有可能超宽,出现纵横向滚动条。
- JS交互,本来默认页面高度不足一屏,结果点击了个“加载更多”,内容超过一屏,滚动条出现,页面主体就会左侧跳动。
- 结构类似几个页面通过头部的水平导航刷新切换,结果有的页面有滚动条,有的没有。造成的结果就是,导航尼玛怎么跳来跳去!
我使用了張鑫旭的方法,但是并沒實現預期的效果。
-
-webkit-appearance: none;
IOS 环境下的按钮都是经过美化的,前端爲了方便會去除這些默認的樣式。
去除完樣式幾乎就變成了這樣:
- html 和 body 百分之百撐滿盒子。
這個沒啥好講的,百分比佈局熟的人都知道。
剩下的就是一些常用的盒子居中,左右浮動,文本溢出隱藏。
Vue項目中的 mixin.css
这个可有可无。
如果你項目中使用了 CSS 預處理器,但是只是用了嵌套語法那可太。。。所以我們不管用不用得到,都應該放一點變量定義,混合等等預處理器的語法,不然你心裏過億的去嗎。姑且我們就叫這個文件為 mixin.css。
@blue: #3190e8;
@bc: #e4e4e4;
@fc:#fff;
// 背景图片地址和大小
.bis(@url) {
background-image: url(@url);
background-repeat: no-repeat;
background-size: 100% 100%;
}
//定位全屏
.allcover{
position:absolute;
top:0;
right:0;
}
//transform上下左右居中
.ctt {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
//定位上下左右居中
.ctp(@width, @height) {
position: absolute;
top: 50%;
left: 50%;
margin-top: -@height/2;
margin-left: -@width/2;
}
//定位上下居中
.tb {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
//定位左右居中
.lr {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
//宽高
.wh(@width, @height){
width: @width;
height: @height;
}
//字体大小、行高、字体
.ft(@size, @line-height) {
font-size: @size;
line-height:@line-height;
}
//字体大小,颜色
.sc(@size, @color){
font-size: @size;
color: @color;
}
//flex 布局和 子元素 对其方式
.fj(@type: space-between){
display: flex;
justify-content: @type;
}
全局的 global.css
这个写项目的时候也是必须的可以放到 reset.css/common.css 里面。主要是写类似后台管理系统进行布局的时候,底部、顶部、侧边栏、能够通过继承有个高度。或者类似下图登录入口就简单是个登录页:
global.css 如下:
html,body,#app{
width: 100%;
height: 100%;
}
二、Vue 中 axios 的封装
这里讲个最简单的:
config文件下
┣✈http.js axios封装
┣✈api.js 接口目录
┣✈config.js 全局配置
首先看全局的配置文件 config.js 文件:
// 不同环境的接口
const proURL = 'http://127.0.0.1:7777/api';
const devURL = 'http://127.0.0.1:7777/api';
// 不同的环境ajax请求前缀设置
const baseURL = process.env.NODE_ENV === 'production'? proURL : devURL;
const config = {
//baseURL
baseURL: baseURL,
// 设置超时时间
timeout: 50000,
// 返回数据类型
responseType: 'json', // default
// 请求的接口,在请求的时候,如axios.get(url,config);这里的url会覆盖掉config中的url
url: '/',
// 请求方法同上
method: 'get', // default
transformRequest: [function (data) {
// 这里可以在发送请求之前对请求数据做处理,比如form-data格式化等,这里可以使用开头引入的Qs(这个模块在安装axios的时候就已经安装了,不需要另外安装)
// data = axios.stringify(data);
// console.log('data',typeof data,data)
return data
}],
transformResponse: [function (data) {
// 这里提前处理返回的数据
if (typeof data === 'string') {
data = JSON.parse(data)
}
return data
}],
// 请求头信息
headers: {
//'Content-Type': 'application/x-www-form-urlencoded',
//'Token': '',
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
},
// parameter参数
params: {},
// post参数,使用axios.post(url,{},data);
data: {},
withCredentials: true
// 当我们把此配置项设置成true的时候,可跨域携带cookie。
}
export default config;
再来看看 http.js 和拦截器:
/**
* http配置
*/
import axios from 'axios';
import config from './config';
import store from '../store';
// 引入axios以及element ui中的loading和message组件
import { Loading , Message} from 'element-ui';
const instance = axios.create(config);
const loadingInstance;
// http请求拦截器
instance.interceptors.request.use(config => {
//写入header token
if (localStorage.getItem('token')) {
config.headers.Authorization = localStorage.getItem('token');
}
// element ui全局菊花图 Loading方法
loadingInstance = Loading.service({
lock: true,
text: '数据加载中,请稍后...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
return config;
}, error => {
// 关闭菊花图
loadingInstance.close();
// 提示错误
Message.error('请求错误');
return Promise.reject(error);
});
// http响应拦截器
instance.interceptors.response.use(response => {
// 响应成功关闭loading
loadingInstance.close();
//对响应数据做些事
var token = response.headers.authorization;
if (token) {
//路由跳转判断依据
store.commit("setToken", token);
// 每次请求携带
localStorage.setItem("token", token);
};
if (response.status === 200) {
const data = response.data;
//后台给的过期接口
if (data.errorCode == 10000) {
//处理token过期操作
logoutFun();
};
};
return response;
}, error => {
// 关闭菊花图
loadingInstance.close();
switch (error.response.status) {
case '401':
Message.error('未授权');
window.location.herf="/login";
break;
case '400':
Message.error('参数错误');
break;
case '403':
// token验证失败
Message.error('登录超时,请重新登录!');
break;
case '404':
Message.error('未找到页面!');
break;
case '500':
Message.error('服务器异常!');
break;
case '504':
Message.error('网关错误!');
break;
default:
Message.error('系统发生未知异常,请稍后重试!');
};
return Promise.reject(error);
});
function logoutFun() {
// 清空本地缓存的token和store里的token
store.commit("setToken", "");
localStorage.removeItem("token");
// 跳转至登录页,并携带用户退出时或token失效时的页面路由,方便登录后直接跳转到此页面。
window.location.herf="/login";
}
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function get(url, params = {}){
return new Promise((resolve, reject) =>{
instance.get(url, {
params: params
})
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
};
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function post(url, params = {}) {
return new Promise((resolve, reject) => {
instance.post(url, JSON.stringify(params))
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data);
});
});
};
export function put(url, params = {}) {
return new Promise((resolve, reject) => {
instance.put(url,JSON.stringify(params))
.then(response => {
resolve(response.data);
}).catch(err => {
reject(err.data);
});
});
};
拦截器这里两个作用一个是加载菊花图,另一个是 token登录。loading 图的制作,elementUI 给的 loading 符合单例模式,服务状态下一次只能打开一个,如果你使用 iview 的话,请使用 Vuex 来控制 loading 图的出现和消失。
还有一个 api.js 文件:
//api接口统一管理
export default {
user:{
superUser:'/api/console/public/signin',//超级管理登录
addUser:'/api/console/user',//用户创建接口,
userQuery:'/api/console/user',//用户列表,
groupQuery:'api/console/group/1000/1/0',//组查询接口
},
article:{
...
}
}
依据网页的不同模块,人多了的话,把负责 user 这块的单独拎出来成一个文件。router.js 也可以这么玩。
main.js 中挂载全局:
//axios
import { get, post , put } from './config/http';
import api from './config/api';
Vue.prototype.$get = get;
Vue.prototype.$post = post;
Vue.prototype.$put = put;
Vue.prototype.$api = api;
项目中使用:
this.$get(this.$api.user.superUser).then(res=>{}).catch(err=>{});
一直到今天才对 axios 的封装有点新的。。。
三、關於Vue項目中配置跨域的問題
如果老天開眼後臺給你配置了跨域,那麽我們就不用去 vue.config.js 中去配置代理跨域了,直接在 axios 的 baseURL 中進行全局配置測試接口即可,例如:
baseURL:'http://test.api.lndl-energy.com/
再在 api.js 接口文件裏面定義接口鏈接即可。但是一般來講開發不可能不會跨域的,除非你兩個人都在服務器上開發,還的是統一文件裡面。這當然是不可能的還是的去配跨域。腳手架的跨域在 vue.config.js(和package.json同級) 裡面配置。
vue.config.json:
// const path = require('path');
// function resolve(dir) {
// return path.join(__dirname, dir)
// }
module.exports = {
// baseUrl type:{string} default:'/'
// 将部署应用程序的基本URL
// 默认情况下,Vue CLI假设您的应用程序将部署在域的根目录下。
// https://www.my-app.com/。如果应用程序部署在子路径上,则需要使用此选项指定子路径。例如,如果您的应用程序部署在https://www.foobar.com/my-app/,集baseUrl到'/my-app/'.
publicPath: '/',
// outputDir: 在npm run build时 生成文件的目录 type:string, default:'dist'
// outputDir: 'dist',
// pages:{ type:Object,Default:undfind }
/*
构建多页面模式的应用程序.每个“页面”都应该有一个相应的JavaScript条目文件。该值应该是一
个对象,其中键是条目的名称,而该值要么是指定其条目、模板和文件名的对象,要么是指定其条目
的字符串,
注意:请保证pages里配置的路径和文件名 在你的文档目录都存在 否则启动服务会报错的
*/
pages: {
index: {
// entry for the page
entry: './src/main.js',
// the source template
template: './public/index.html',
// output as dist/index.html
filename: 'index.html'
}
},
// when using the entry-only string format,
// template is inferred to be `public/subpage.html`
// and falls back to `public/index.html` if not found.
// Output filename is inferred to be `subpage.html`.
// subpage: 'src/subpage/main.js'
// },
//lintOnSave:{ type:Boolean default:true } 问你是否使用eslint
lintOnSave: false,
// productionSourceMap:{ type:Bollean,default:true } 生产源映射
// 如果您不需要生产时的源映射,那么将此设置为false可以加速生产构建
productionSourceMap: false,
// webpack 配置~
// chainWebpack: () => {},
// configureWebpack: () => {
// if (process.env.NODE_ENV === 'production') {
// // mutate config for production...
// } else {
// // mutate for development...
// }
// },
// vue-loader 配置
// vueLoader: {},
css: {
// // 是否提取css生成单独的文件 默认 true
// extract: true,
// // 使用 CSS source maps?
// sourceMap: false,
// loader配置
loaderOptions: {
// 向预处理器 Loader 传递配置选项
scss: { // 配置scss(其他样式解析用法一致)
javascriptEnabled: true // 设置为true
}
},
// // 使用 css Modules
// modules: false
},
// devServer:{type:Object}它支持webPack-dev-server的所有选项
devServer: {
port: 8888, // 端口号
host: 'localhost', //host: "0.0.0.0",如果是真机测试,就使用这个IP
https: false, // https:{type:Boolean}
open: true, //配置自动启动浏览器
hotOnly: false, //热更新(webpack已实现了,这里false即可)
//disableHostCheck: true,
proxy: {
//配置跨域
'/api': {
target: "http://test.api.lndl-energy.com/wallet",
ws:true,
changOrigin:true,
pathRewrite:{
'^/api':'/'
}
}
}
}
};
待完善 vue-cli环境变量
四、elementUI
- elementUI 组件的名可以当类名使用
- 控制台审查元素出现的类名,在编辑器里面必须使用深度选择器,来改变样式 /deep/,不然不起作用。
aslid,v-for权限管理一级二级菜单
elementUi自定义字体图标库,icon asset font,通过for循环的ID来渲染font类名
unique-opened :unique-opened="true" 选择框之允许打开一列
.el-menu{border-right:1px solid red;}展开多一像素
el-menu collapse 是否折叠,折叠面板变小。el-aside:width="collapse===false?64px;200px;"
el-menu 开启路由调转 router,以#为根开始跳转,default-active=index激活状态,使用session保存,created创建
router-view中使用el-card作为背景
el-row 和el-col,el-input使用span解决,gutter解决中间的间隙