发表于: 2019-11-16 17:02:10

0 1051


一、Vue.cli的目录结构

①  vue.2.0

|- project

  |-node_modules       //node安装的依赖包(npm i

  |-build               //项目构建的相关代码(不管)

  |-config              //项目开发环境配置(不管)

  |-src                 //源码目录

  |  |-assets           //资源目录

  |  |  |-logo.png

  |  |-components       //组件目录

  |  |  |- common       //放置公共组件

  |  |  |- views         // 视图组件(其他页面)

  |  |-router          

  |  |  |-router.js     //前端路由

  |  |-App.vue         //根组件(页面入口)

  |  |-main.js          //入口js文件。加载各种公共组件(路由及其他) 

  |-index.html          //入口页面,

  |-package.json        // npm包配置文件,里面定义了项目的npm脚本,依赖包等信息

  |-README.md        //项目介绍

② vue.3.0

|- project

  |-node_modules        //node安装的依赖包

  |-public           

  |  |-favicon.ico

  |  |-index.html       //入口页面

  |-src                 // 源码目录

  |  |-assets           //资源目录,这里的资源会被wabpack构建

  |  |  |-logo.png

  |  |-components       //组件目录

  |  |  |- common       //放置公共组件

  |  |  |-HelloWorld.vue

  |  |-router          

  |  |  |-router.js     //前端路由

  |  |-App.vue          //根组件

  |  |-main.js          //入口js文件

  |-package.json        // npm包配置文件,里面定义了项目的npm脚本,依赖包等信息

  |-README.md           //项目介绍

编写index.js(默认模板)

项目中最外层的页面(title及meta标签等)都设置在这里。

设置#app容器

再设置好noscript标签

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
    <meta content="yes" name="apple-mobile-web-app-capable">
    <meta content="black" name="apple-mobile-web-app-status-bar-style">
    <meta content="telephone=no" name="format-detection">
    <meta content="email=no" name="format-detection">
    <title>carrtcms</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but my-project doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

三、配置根组件模板(App.vue)

设置#app挂载容器,

设置公用样式(项目背景底色,组件切换效果(vue自带组件transition),按钮动画效果,input输入框效果等)

<template>
  <div id="app" v-cloak>
    <transition name="fade" mode="out-in">
      <router-view v-if="show" />
    </transition>
    <!-- <router-view/> -->
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      show: true,
      isLoading: false,
    };
  },
  methods:{
    onRefresh() {
      setTimeout(() => {
        // 刷新
        this.$router.go(0);
        this.isLoading = false;
      }, 500);
    }
  }
}
</script>

<style>
#app {
  font-family'Avenir'HelveticaArialsans-serif;
  -webkit-font-smoothingantialiased;
  -moz-osx-font-smoothinggrayscale;
  text-aligncenter;
  color#2c3e50;
  margin-top60px;
}

html,
body {
  height100%;
  background#f5f5f5;
}

/* 添加过渡样式: */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.15s;
}
.fade-enter.fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity0;
}

[v-cloak] {
  displaynone;
}

/* 按钮动画 */
button,
.animateBtn {
  positionrelative;
  overflowhidden;
  transitionall 0.3s;
}
button::after,
.animateBtn::after {
  content"";
  displayblock;
  positionabsolute;
  width100%;
  height100%;
  top0;
  left0;
  pointer-eventsnone;
  background-imageradial-gradient(circle#666 10%transparent 10.01%);
  background-repeatno-repeat;
  background-position50%;
  transformscale(1010);
  opacity0;
  transition: transform 0.3s, opacity 0.5s;
}
button:active::after,
.animateBtn:active::after {
  transformscale(00);
  opacity0.3;
  transition0s;
}
button:active,
.animateBtn:active {
  animation: btnanimte 0.1s ease-in;
}
@keyframes btnanimte {
  0%,
  100% {
    transformscale(1);
  }
  50% {
    transformscale(0.85);
  }
}


四、在main.js上挂载

安装并引入组件库Element UI(web端)

在项目目录下执行命令,安装axios及qs,并引入main.js

npm install axios -S

npm install qs

配置组件(aside.vue)并注册引入

全局配置(封装httpRequest)

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 'axios';
import qs from 'qs';
Vue.use(ElementUI)

Vue.config.productionTip = false

axios.defaults.baseURL = "";
// 接口url
Vue.prototype.httpPath = "";
// axios.defaults.withCredentials = true
Vue.prototype.$axios = axios;

//引入侧边导航组件
import aside from './components/common/aside.vue';
Vue.component('aside'aside);

//封装httpRequest
Vue.prototype.$req = httpRequest;

function httpRequest(urlmethoddata = {}, ) {
    //将method字符转换为小写
    method = method.toLowerCase();
    let axiosOptions = {
        url: Vue.prototype.httpPath + url,
        method: method
    };
    if (method === 'get' || method === 'delete') {
        axiosOptions.params = data;
    } else {
        axiosOptions.data = qs.stringify(data);
    }
    return new Promise((resolvereject=> {
        axios(axiosOptions).then(res => {
                if (res.data.code == -1) {
                    Vue.prototype.$toast('未登录');
                    console.log('目标页'this.$router)
                    // let urlname = this.$router.history.current.fullPath;
                    setTimeout(() => {
                        this.$router.replace({
                            name: 'login'
                            // query: {
                            //     urlname
                            // }
                        })
                    }, 3000);
                } else {
                    //成功
                    resolve(res.data);
                }
            })
            .catch(err => {
                //失败
                reject(err)
            })
    })

}


// 实例化一个Vue
new Vue({
  el: '#app',
  router,
  // 声明有哪些组件
  components: { App },
  // 表示(使用)加载App.vue 
  template: '<App/>'  // 其中的<div id="app"></div> 会替换index.html里面的<div id="app"></div>

})


五、Vue异步加载组件

异步加载组件就是在定义组件的时候什么都不做,只有当组件第一次使用的时候才进行加载和渲染。

实现的三种方式:

1)webpack代码分割。

        component:resolve => require(['@/component/helloworld'],resolve);(这里的@是相对路径,要看webpack的你自己是怎么配置的)

        这里的require是AMD规范的引入关键词,resolve是全部引入成功以后的回调函数,第一个参数是依赖, require会先引入依赖模块,再执行回调函数。

2)webpack2+es6。

        component:() => import('./component/helloworld');

        import函数是es6里面的新方法,主要是进行异步加载的,返回一个promise对象。import命令能够接受什么参数,import()函数就能接受什么参数,两者区别主要是后者为动态加载。

3)webpack另一种代码分割。   

       component: r => require.ensure([], () => r(require('./helloworld.vue')), 'group-foo')

编写router.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    //侧面导航 路由
    {
      path:'/',//侧面导航               vuecli对@进行了定义,@相当于src文件夹
      componentresolve => require (['@components/common/aside'],resolve),
      //子页面
      children:[
      // {
      //   path:'/',//首页
      //   name:'/',
      //   component: resolve => require (['@components/views/welcome'],resolve),
      // },
      {
        path:'/article',//文章列表页
        name:'/article',
        componentresolve => require (['@components/views/article'], resolve),
      }
     ]
    },
    //非侧面导航
    {
      path: '/welcome'// 欢迎页
      name: 'welcome',
      componentresolve => require(['@/components/view/login/welcome'], resolve),
    }, 
    {
      path: '/login'// 登陆页
      name: 'login',
      componentresolve => require(['@/components/view/login/login'], resolve),
    },
  ]
})


七、Vue的跨域

  跨域指浏览器不允许当前页面的所在的源去请求另一个源的数据。源指协议,端口,域名。只要这个3个中有一个不同就是跨域。

#协议跨域

http://a.baidu.com访问https://a.baidu.com;

#端口跨域

http://a.baidu.com:8080访问http://a.baidu.com:80;

#域名跨域

http://a.baidu.com访问http://b.baidu.com;

解决方案

proxyTable (vue)(仅开发)

  这里vue脚手架生成的标准项目为准。一般在项目config目录下面有个index文件。里面格式如下:

'use strict'

const path = require('path')

module.exports = {

    dev: {

        // Paths

        assetsSubDirectory: 'static',

        assetsPublicPath: '/',

        proxyTable: {

            '/api': {

                target: 'http://url',//后端接口地址

                changeOrigin: true,//是否允许跨越

                pathRewrite: {

                    '^/api': '/api',//重写,

                }

            }

        },

        host: '192.168.0.104',

        port: 8081,

        autoOpenBrowser: false,

        errorOverlay: true,

        notifyOnErrors: true,

        poll: false,

        useEslint: true,

        showEslintErrorsInOverlay: false,

        devtool: 'eval-source-map',

        cacheBusting: true,

        cssSourceMap: false,

    },

}

  上面配置中,我们根据实际情况只需要修改proxyTable对于配置即可。假设我后端请求地址是http://url,所有api的接口url都以/api开头。所以首先需要匹配所有以/api开头的.然后修改target的地址为http://url。最后修改pathRewrite地址。将前缀 '^api' 转为 '/api'。如果本身的接口地址就有 '/api' 这种通用前缀,就可以把 pathRewrite 删掉。注意这个方式只能在开发环境中使用。

CORS(有风险)(需后端配合)(支持开发及生产)

  CORS即跨源资源共享,它定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。它是一个妥协,有更大的灵活性,但比起简单地允许所有这些的要求来说更加安全。但是CORS也具有一定的风险性,比如请求中只能说明来自于一个特定的域但不能验证是否可信,而且也容易被第三方入侵。 这里一般需要后端配合,开启cors。一般各种语言都有类似的包。比如NodeJS的koa2-cors

var koa = require('koa');

//npm install --save koa2-cors

var cors = require('koa2-cors');

var app = koa();

//开启

app.use(cors());

这个方式解决的跨越问题支持开发和生产环境。但是有一定的安全性问题。

Nginx (需后端配合)(支持开发与生产)

  当我们明白跨越的含义之后。只要解决了'源'的问题。那么跨越也就不存在了。这里我们便会想到proxy,同时也会想到Nginx。

   location /api/ {

       proxy_pass http://url;

   }

   ##  /no 表示以/no开头的url,包括/no1,no/son,或者no/son/grandson

   ##  若 proxy_pass最后为/ 如http://localhost:3000/;匹配/no/son,则真实匹配为http://localhost:3000/son

   location /no {

       proxy_pass http://url;

   }

   ##  /ok/表示精确匹配以ok开头的url,/ok2是匹配不到的,/ok/son则可以

   location /ok/ {

       proxy_pass http://url;

   }

}

我们只需要在部署静态资源配置下面加上红框里面的配置就可以了。同时这个方法支持开发环境和生产环境。

后端程序代理

  当然上面2个方法都需要后端的配合和需要修改服务器配置。所有还有一种方法不需要他们配合 ,我们自己就可以做到。就是我们自己启一个后端程序做代理。然后把所有的请求转发到服务器。这里要用到node的一个包http-proxy-middleware。关键代码(express)如下

var proxy = require('http-proxy-middleware');

var app = express();

app.use('/api', proxy({

       target: 'http://10.119.168.87:4000', 

       changeOrigin: true

}));

八、配置跨域

在config的index.js配置文件的dev中,添加proxyTable,使用api替代服务器地址

proxyTable: {

      '/api': {

        target: 'http://url', //接口地址

        changeOrigin: true,

        pathRewrite: {

          '^/api': ''

        }

      },

},

九、Views

由任务详情得知,我们需要两个主页面

登录页(login)和后台页(article),其余页面是当做后台页的子页面



返回列表 返回列表
评论

    分享到