① 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', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
html,
body {
height: 100%;
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 */ {
opacity: 0;
}
[v-cloak] {
display: none;
}
/* 按钮动画 */
button,
.animateBtn {
position: relative;
overflow: hidden;
transition: all 0.3s;
}
button::after,
.animateBtn::after {
content: "";
display: block;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
pointer-events: none;
background-image: radial-gradient(circle, #666 10%, transparent 10.01%);
background-repeat: no-repeat;
background-position: 50%;
transform: scale(10, 10);
opacity: 0;
transition: transform 0.3s, opacity 0.5s;
}
button:active::after,
.animateBtn:active::after {
transform: scale(0, 0);
opacity: 0.3;
transition: 0s;
}
button:active,
.animateBtn:active {
animation: btnanimte 0.1s ease-in;
}
@keyframes btnanimte {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(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(url, method, data = {}, ) {
//将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((resolve, reject) => {
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文件夹
component: resolve => require (['@components/common/aside'],resolve),
//子页面
children:[
// {
// path:'/',//首页
// name:'/',
// component: resolve => require (['@components/views/welcome'],resolve),
// },
{
path:'/article',//文章列表页
name:'/article',
component: resolve => require (['@components/views/article'], resolve),
}
]
},
//非侧面导航
{
path: '/welcome', // 欢迎页
name: 'welcome',
component: resolve => require(['@/components/view/login/welcome'], resolve),
},
{
path: '/login', // 登陆页
name: 'login',
component: resolve => 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),其余页面是当做后台页的子页面
评论