美文网首页
vue-cli搭建项目

vue-cli搭建项目

作者: Issho | 来源:发表于2020-01-17 14:19 被阅读0次

    ☼ 注:笔者的文章是根据自己当前项目做的笔记,具体应用请参照自己实际项目情况

    1、创建应用
    npm install -g @vue/cli-service-global
    vue create my-vue-project
    cd my-vue-project
    npm run serve
    
    2、配置axios及proxy跨域代理

    ⑴ 安装http-proxy-middleware

    npm install http-proxy-middleware --save
    

    ⑵ 在根目录新建一个vue.config.js文件

    module.exports = {
        devServer: {
            proxy: {
                '/c': {
                    target: 'https://10.8.20.25',
                    changeOrigin: true,
                    secure: false
                },
                '/v1': {
                    target: 'https://10.8.20.25',
                    changeOrigin: true,
                    secure: false
                }
            }
        }
    }
    

    ⑶ 安装axios

    npm install axios --save
    

    ⑷ 在main.js中引用

    import axios from 'axios'
    
    Vue.prototype.axios = axios.create({
      baseURL: window.location.origin
    })
    

    ⑸ 在业务中使用

    // 开发环境或预发布环境
    const apiUrl = window.location.origin.includes('cms') ? 'v1/web/estatewebadmin' : 'clife-estate-api-web-admin'
    this.url = `/${apiUrl}/estate/merchant/detail/${this.id}.do`
    axios.post(this.url, { carNo: this.carNo }).then(res => console.log(res)).catch(err => console.log(err))
    
    3、配置基本路径,解决打包首页空白问题

    在vue.config.js文件中,添加以下配置

    module.exports = {
        publicPath: './', //基本路径,解决打包空白问题
    }
    
    4、配置rem方案

    ⑴ 在src目录下新建一个utils目录(用来放置工具函数),在utils目录下新建一个rem.js文件

    /*设置REM方案*/
    remFont()
    window.addEventListener('resize', function () {
        remFont();
        // console.log(window.innerWidth)
    });
    function remFont() { 
        var html = document.getElementsByTagName('html')[0];
        var width = window.innerWidth;
        var font_Size = 0;
        if(width >= 320 && width <= 1024){
          font_Size = 100/375 * width;
        }else if(width<320){
          font_Size = 100/375 * 320;
        }else{
          font_Size = 100/375 * 1024;
        }
        html.style.fontSize = font_Size + 'px';
    }
    

    ⑵ 在main.js文件中,引入rem.js

    import './utils/rem'
    

    ⑶ 安装postcss-px2rem

    npm i postcss-px2rem --save
    

    ⑷ 在vue.config.js中配置

    const px2rem = require('postcss-px2rem')
    const postcss = px2rem({
        remUnit: 100   //基准大小 baseSize,需要和rem.js中相同
    })
    module.exports = {
        css: {
            loaderOptions: {
                postcss: {
                    plugins: [
                        postcss
                    ]
                }
            }
        }
    }
    
    5、引入element-ui,配置按需加载

    ⑴ 安装element-ui

    npm i element-ui --save
    

    ⑵ 在babel.config.js中配置

    module.exports = {
      presets: [
        '@vue/app'
      ],
      plugins: [["component",
        {
          "libraryName": "element-ui",
          "styleLibraryName": "theme-chalk"
        }
      ]]
    }
    

    ⑶ 在main.js中引入

    import { Button, Message } from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    Vue.use(Button)
    Vue.component(Message.name, Message)
    Vue.prototype.$message = Message
    
    6、引入阿里iocn

    ⑴ 在src文件夹下新建一个assets文件夹,再新建一个iconfont文件夹,把阿里图库生成的文件放到文件夹下
    ⑵ 在main.js中引入

    import '@/assets/iconfont/iconfont.css'
    
    7、引入vue-echarts图表库

    ⑴ 安装vue-echarts

    npm install echarts vue-echarts --save
    

    ⑵ 在vue.config.js中配置

    module.exports = {
        transpileDependencies: [
            'vue-echarts',
            'resize-detector'
        ]
    }
    

    ⑶ 在main.js中引入

    import ECharts from 'vue-echarts'
    import chinaJson from 'echarts/map/json/china.json'
    import 'echarts/lib/chart/map'
    import 'echarts/lib/component/geo'
    
    ECharts.registerMap('china', chinaJson)
    Vue.prototype.$echarts = ECharts
    Vue.component('v-chart', ECharts)
    

    ⑷ 使用

    <div class="map">
        <v-chart :options="mapOptions" :autoresize="true"></v-chart>
    </div>
    
    8、配置路由

    ⑴ 安装vue-router

    npm install vue-router --save
    

    ⑵ 在src目录下新建一个router.js文件

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter)
    
    const baseUrl = './pages/'
    const communityUrl = './pages/community/components/'
    
    const routes = [
        { path: '/', redirect: '/dataCenter' },
        { path: '/dataCenter', component: () => import(`${baseUrl}dataCenter`) },
        { path: '/community', component: () => import(`${baseUrl}community`), children: [
            {
                path: '/',
                component: () => import(`${communityUrl}guardView`)
            }, {
                path: 'parkGuard',
                component: () => import(`${communityUrl}parkGuard`)
            }
        ] }
    ]
    
    export const router = new VueRouter({
        routes
    })
    // 登录状态重定向
    router.beforeEach((to, from, next) => {
        if (!loginStatus && to.path !== '/login') {
            next('/login')
        } else {
            next()
        }
    })
    

    ⑶ 在main.js中挂载

    import { router } from './routes'
    
    new Vue({
      router,
      render: h => h(App),
    }).$mount('#app')
    
    9、配置vuex

    ⑴ 安装vuex

    npm i vuex --save
    

    ⑵ 在src目录下新建一个store文件夹,再新建一个index.js文件

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    export default new Vuex.Store({
        state: {
            isCollapse: false
        },
        mutations: {
            toCollapse (state, bool) {
                state.isCollapse = bool
            }
        }
    })
    

    ⑶ 在业务代码中使用

    <template>
       <el-menu-item>
            <i v-if="!isCollapse" class="el-icon-s-fold" @click="toCollapse(true)"></i>
            <i v-else class="el-icon-s-unfold" @click="toCollapse(false)"></i>
       </el-menu-item>
    </template>
    <script>
    import { mapMutations, mapState } from 'vuex' 
    export default {
      computed: {
        ...mapState(['isCollapse'])
      },
      methods: {
        ...mapMutations(['toCollapse']),
    }
    </script>
    
    10、结合axios拦截器和vuex模块化封装管理请求
    ⑴ 在src下新建一个api目录,用来统一管理接口地址

    在api目录下新建一个config.js,配置baseURL

    const HOST = window.location.origin
    
    const apiUrl = HOST.includes('cms') ? '/v1/web/estatewebadmin' : '/clife-estate-api-web-admin'
    
    export default HOST + apiUrl
    

    再新建一个axios.js配置拦截器

    import axios from 'axios'
    import qs from 'qs'
    import baseURL from './config'
    import vm from '@/main'
    
    const Axios = axios.create({
        baseURL,
        withCredentials: true, // 是否允许跨域请求携带cookie
        responseType: 'json', // 服务器响应的数据类型, 默认json
        headers: {
            'Content-Type': 'application/json;charset=UTF-8' // 请求头content-type类型, 默认json
        }
    })
    
    let loadingInstance = null
    
    const loadingOn = loading => {
        if (!loadingInstance && loading !== false) {
            loadingInstance = vm.$loading({ target: '.el-main>div' })
        }
    }
    
    const loadingOff = () => {
        loadingInstance && setTimeout(() => {
            loadingInstance.close()
            loadingInstance = null
        }, 500)
    }
    
    // 请求拦截器
    Axios.interceptors.request.use(
        config => {
            // 检测网络
            if (!navigator.onLine){
                vm.$message.error('当前网络已断开,请联网重试!')
                return
            }
            // 针对post请求和get请求处理
            if (config.method === 'post') {
                // 可以把自定义的信息和参数一起传过来,再做统一处理
                const { headers, responseType, param, loading } = config.data || {}
                // 开启loading
                loadingOn(loading)
                // 如果重写了headers, 则替换
                if (headers) {
                    config.headers = headers
                }
                // 如果重写了responseType, 则替换
                if (responseType) {
                    config.responseType = responseType
                }
                // 如果请求头Content-Type为表单形式,则通过qs插件把参数做相关处理
                config.data = config.headers['Content-Type'] === 'application/x-www-form-urlencoded' ? qs.stringify(param) : param
            } else {
                // 开启loading
                loadingOn(config.loading)
                // 参数
                config.params = config.param
            }
            // 取消请求
            config.cancelToken = vm.$store.state.Root.source.token
    
            return config
        },
        err => {
            loadingOff()
            return Promise.reject(err)
        }
    )
    
    Axios.interceptors.response.use(
        response => {
            loadingOff()
            const { data, config } = response || {}
            // code为0,返回响应数据
            if (+data.code === 0) {
                return data
            }
            // 文件流格式
            if (config.responseType === 'blob') {
                // message提示后台返回json格式的错误信息
                if (data.type === 'application/json') {
                    let reader = new FileReader()
                    reader.onload = e => JSON.parse(e.target.result).msg
                    reader.readAsText(data)
                    return
                }
                // 需要针对IE做兼容,所以直接返回blob对象,再针对不同浏览器做url转化处理
                return  new Blob([data], { type: data.type })
            }
    
            // 后台返回用户未登录或用户不存在
            if (+data.code === 100010110 || +data.code === 100021401) {
    
                return
            }
    
            // code非0
            vm.$message(data.msg)
            return Promise.reject(data)
    
    
        },
        err => {
            loadingOff()
            if (!err.response) {
                // 如果是取消请求导致的错误,则不做msg提示
                return Promise.reject(err)
            }
            vm.$message.warning('服务调用失败,请稍后重试!')
            return Promise.reject(err)
        }
    )
    
    export default Axios
    

    然后按模块划分接口,比如 /api/setting/basic/project.js

    import axios from '@/api/axios'
    
    export default {
        queryProject: data => axios.post('/estate/project/queryProject.do', data)
    }
    
    ⑵ 在src目录下新建一个store目录, 把接口请求方法和数据处理统一放在vuex里完成

    store目录下新建一个root.js,用来处理全局方法和数据,比如取消axios请求或收缩菜单等

    export default {
        namespaced: true,
        state: {
            isCollapse: false,
            source: { token: null, cancel: null }
        },
        mutations: {
            // 改变侧边菜单伸缩状态
            toCollapse: (state, bool) => {
                state.isCollapse = bool
            },
            // 取消axios请求
            soureToken: (state, source) => {
                state.source = source
            }
        }
    }
    

    再按模块划分不同的modules,和api下的模块保持一致,比如store/setting/basic/project.js

    import Project from '@/api/setting/basic/project'
    
    export default {
        namespaced: true,
        state: {
            projectRecord: [],
            totalRows: 0
        },
        actions: {
            queryProject: async ({ state }, params) => {
                const data = await Project.queryProject(params)
                try {
                    state.projectRecord = data.data.record
                    state.totalRows = data.data.totalRows
                } catch (err) {
                    return Promise.reject(err)
                }
            }
        },
        getters: {
            projectList: state => {
                return state.projectRecord.map(item => ({
                    id: item.projectId,
                    name: item.projectName
                }))
            }
        }
    }
    

    然后在setting下新建一个index.js引入各个小模块的modules

    import Project from './basic/project'
    
    export default {
        namespaced: true,
        modules: {
            Project
        }
    }
    

    最后在store下新建一个index.js引入各个大模块的modules

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    import Root from './root'
    import Setting from './setting'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
        modules: {
           Root, Setting
       }
    })
    
    ⑶ 在页面调用请求,获取处理后的数据结果
    import { mapState, mapGetters, mapMutations } from 'vuex'
    export default {
        computed: {
            ...mapState('Root', ['source']),
            ...mapState('Setting/Project', ['projectRecord']),
            ...mapGetters('Setting/Project', ['projectList']),
        },
        methods: {
            ...mapMutations('Root', ['soureToken']),
            handleClick() {
                this.source.cancel && this.source.cancel()
                this.soureToken(this.$axios.CancelToken.source())
                this.queryProject()
            },
            queryProject() {
                this.$store.dispatch('Setting/Project/queryProject', {
                    param: {
                        data: {
                            project: {
                                projStatus: 1,
                                ...this.formValue
                            },
                            pager: {
                                pageRows: 10,
                                pageIndex: 1,
                                paged: true
                            },
                            orderBy: {
                                orderColumn: 'createTime',
                                orderType: 'desc'
                            }
                        }
                    },
                    // loading: false
                }).then(() => {
                    console.log(this.projectRecord)
                })
            }
        },
        created() {
            this.queryProject()
        }
    }
    

    相关文章

      网友评论

          本文标题:vue-cli搭建项目

          本文链接:https://www.haomeiwen.com/subject/xqrczctx.html