Vue 搭建项目如何配置进行无脑开发

使用 Vue-cli 创建完项目,还需要进行一些配置才能进入开发模式,如果有老大当然是老大来做这些,但是万一这是落到你头上,可不懵逼了,简单的我总结下我配置的流程。

一、初始化样式

在 Jquery 的网页时代我们写项目的时候,为了去除 HTML 默认标签的影响,最常用的是雅虎的 reset.css 当然你也会参考别人自己写的。目前比较全的CSS重设(reset)方法总结

转眼到了 Vue 横行的 MVVM 时代。

Vue 项目的 reset.css或common.css

引入这个东西主要是解决两个问题:

  1. 隐藏浏览器的侧边滚动条,避免对布局的影响。
  2. 去除 HTML 标签的默认样式。

就算您不看下面的代码,在写项目的时候,也得把下面代码用到你的项目中。一般讲引用的位置有两个可以选择的地方:

  1. 第一个地方:main.js 文件(推荐)
import '../public/css/reset.css';
  1. 第二个地方在 App.vue 中引用,同时记住我们在引入的时候去掉 scoped
<template>
    <div id="app" class="fillcontain">
            <router-view></router-view>
    </div>
</template>

<script>
    export default {
        
    }
</script>

<style lang="less">
    @import './style/common';
</style>

针对上面的样式文件做几点解释:

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;
}
/*height:auto是必需的,否则,如果原始图片有设定height,max-width生效的时候,图片就会被水平压缩。
强制height为auto可以确保宽度不超出的同时使图片保持原来的比例。*/
img{
    max-width: 100%;
    height: auto !important;
}
  1. -webkit-tap-highlight-color:transparent;
    这个属性只用于 iOS (iPhone和iPad)。当你点击一个链接或者通过 Javascript 定义的可点击元素的时候,它就会出现一个半透明的灰色背景。把 -webkit-tap-highlight-color 设置为透明,重设它。
  2. -webkit-font-smoothing: antialiased;
    -webkit-font-smoothing 控制的字体渲染只对MacOS的Webkit有效。具体参考这个博客:CSS 中 -webkit-font-smoothing: antialiased 反而让字体更难看了?
  3. outline: none;
    可以在 pc 端为 a 标签定义这个样式的目的是为了取消ie浏览器下点击a标签时出现的虚线和取消chrome下默认的文本框聚焦样式。
  4. ::-webkit-scrollbar 页面溢出的滚动条
    这个千万记住,一定一定要加上,不然你在布局的时候,就尴尬了。我主要遇见两个问题:
  • 页面过宽会跳动,去看看这个页面出现滚动条的时候没有跳动demo感受下导航跳动问题。
  • 第二个就是页面导航条也是 body 的一部分,如果去掉滚动条的时候,你页面恰好平铺整个页面,但是滚动条出现可能导致盒子剩余宽度太窄,整个布局盒子掉了下来,在或者滚动条压住了内容。

这个滚动条这把我给折腾的够呛,那就多说几句,不重新写篇关于这个的文章了。还有个常见的问题就是页面水平居中布局的时候,水平居中布局与滚动条跳动的千年难题,这个问题也是常见,挺难弄的。主要待解决的问题是:

当前web届,绝大多数的页面间布局都是水平居中布局,主体定个宽度,然后margin: 0 auto的节奏~然而,这种> > 布局有一个存在一个影响用户体验的隐患。应该都知道,现代浏览器滚动条默认是overflow:auto类型的,也就是如> 果尺寸不足一屏,没有滚动条;超出,出现滚动条。于是,问题来了:

  • 信息流页面,新出现的页面有可能超宽,出现纵横向滚动条。
  • JS交互,本来默认页面高度不足一屏,结果点击了个“加载更多”,内容超过一屏,滚动条出现,页面主体就会左侧跳动。
  • 结构类似几个页面通过头部的水平导航刷新切换,结果有的页面有滚动条,有的没有。造成的结果就是,导航尼玛怎么跳来跳去!

張鑫旭推荐的方法:

html {
  overflow-y: scroll;
}

:root {
  overflow-y: auto;
  overflow-x: hidden;
}

:root body {
  position: absolute;
}

body {
  width: 100vw;
  overflow: hidden;
}

居中布局倒是没问题,有问题就是如果内容布满屏幕,同时高度超出屏幕产生了滚动条,就会发现滚动条覆盖了文字。所以单页面应用需要铺满屏幕,避免产生滚动条还是使用::-webkit-scrollbar

  1. -webkit-appearance: none;
    IOS 环境下的按钮都是经过美化的,前端爲了方便會去除這些默認的樣式。
    去除完樣式幾乎就變成了這樣:
    無默認樣式的按鈕
  2. 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

  1. elementUI 组件的名可以当类名使用
  2. 使用elementUI 组件在控制台审查元素出现的类名,因为编辑代码里面没有,所以在编辑器里面必须使用深度选择器穿透来改变样式,使用 /deep/ 。
  3. <el-container>:外层容器。当子元素中包含 <el-header> 或 <el-footer> 时,全部子元素会垂直上下排列,否则会水平左右排列。
    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创建

<el-table-column type="index" width="50">索引列

router-view中使用el-card作为背景

el-row 和el-col,el-input使用span解决,gutter解决中间的间隙

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容

  • 基于Vue的一些资料 内容 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 element★...
    尝了又尝阅读 1,140评论 0 1
  • 前端开发面试题 面试题目: 根据你的等级和职位的变化,入门级到专家级,广度和深度都会有所增加。 题目类型: 理论知...
    怡宝丶阅读 2,569评论 0 7
  • 连续两天,我写了一些玫瑰呀,爱情呀,浪漫呀,老妪聊发少女狂,狠狠地yy了自己一下,过了一把狂想瘾。 而此刻,貌似心...
    鱼1967阅读 403评论 2 1
  • 尼:虽然我心中明白,但不知怎的,这听起来却象是,我们不该在意在关系中别人对我们做了什么。他们可以为所欲为,只要我们...
    May的日志阅读 392评论 1 1
  • 今天在做ARP抓包程序
    af4c8197e922阅读 193评论 0 1