Vue安装
cnpm install vue
# 全局安装 vue-cli
$ cnpm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack my-project
# 这里需要进行一些配置,默认回车即可
This will install Vue 2.x version of the template.
For Vue 1.x use: vue init webpack#1.0 my-project
? Project name my-project
? Project description A Vue.js project
? Author runoob <test@runoob.com>
? Vue build standalone
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Setup unit tests with Karma + Mocha? Yes
? Setup e2e tests with Nightwatch? Yes
vue-cli · Generated "my-project".
To get started:
cd my-project
npm install
npm run dev
Documentation can be found at https://vuejs-templates.github.io/webpack
进入项目并安装运行
$ cd my-project
$ cnpm install
$ cnpm run dev
DONE Compiled successfully in 4388ms
> Listening at http://localhost:8080
在windows下使用pycharm新建vue项目,随后通过packet.jsonbuild得到dist的目录,将目录拷贝到django项目之中。
如果没有config文件夹,则添加vue.config.js
const debug = process.env.NODE_ENV !== 'production'
module.exports = {
publicPath: './', // 根域上下文目录,这里一定记得改
outputDir: 'dist', // 构建输出目录
assetsDir: 'static', // 静态资源目录 (js, css, img, fonts)
lintOnSave: false, // 是否开启eslint保存检测,有效值:ture | false | 'error'
runtimeCompiler: true, // 运行时版本是否需要编译
transpileDependencies: [], // 默认babel-loader忽略mode_modules,这里可增加例外的依赖包名
productionSourceMap: true, // 是否在构建生产包时生成 sourceMap 文件,false将提高构建速度
configureWebpack: config => { // webpack配置,值位对象时会合并配置,为方法时会改写配置
if (debug) { // 开发环境配置
config.devtool = 'cheap-module-eval-source-map'
} else { // 生产环境配置
}
// Object.assign(config, { // 开发生产共同配置
// resolve: {
// alias: {
// '@': path.resolve(__dirname, './src'),
// '@c': path.resolve(__dirname, './src/components'),
// 'vue$': 'vue/dist/vue.esm.js'
// }
// }
// })
},
chainWebpack: config => { // webpack链接API,用于生成和修改webapck配置,https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
if (debug) {
// 本地开发配置
} else {
// 生产开发配置
}
},
parallel: require('os').cpus().length > 1, // 构建时开启多进程处理babel编译
pluginOptions: { // 第三方插件配置
},
pwa: { // 单页插件相关配置 https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
},
devServer: {
open: true,
host: 'localhost',
port: 8080,
https: false,
hotOnly: false,
proxy: { // 配置跨域
'/api': {
target: '', //接口域名
ws: true, //是否代理websockets
changOrigin: true, //是否跨域
pathRewrite: { //重置路径
'^/api': ''
}
}
},
before: app => { }
}
}
Vue目录含义
目录/文件 | 说明 |
---|---|
build | 项目构建(webpack)相关代码 |
config | 配置目录,包括端口号等。我们初学可以使用默认的。 |
node_modules | npm 加载的项目依赖模块 |
src | 这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件: |
src/assets | 放置一些图片,如logo等。 |
src/components | 目录里面放了一个组件文件,可以不用。 |
src/App.vue | 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。 |
src/main.js | 项目的核心文件。 |
static | 静态资源目录,如图片、字体等。 |
test | 初始测试目录,可删除 |
.xxxx文件 | 这些是一些配置文件,包括语法配置,git配置等。 |
index.html | 首页入口文件,你可以添加一些 meta 信息或统计代码啥的。 |
package.json | 项目配置文件。 |
README.md | 项目的说明文档,markdown 格式 |
dist | build后生成目录 |
App.vue是我们的根组件,所有页面都是在App.vue下进行切换的。其实你也可以理解为所有的路由也是App.vue的子组件。所以我将router标示为App.vue的子组件。最直接的使用就是导航栏。
什么是前后端分离
简单理解:假定A表示IP,B表示端口,网页部署在 A1:B1
而提供服务的后端django server可以在A2:B2,例如我们可以讲编译过后的vue项目部署至nginx服务器,通过80端口访问,而django在8000端口提供服务从而将前端项目和后端项目剥离
那么项目交互的点是什么呢,其实就是一组api接口,对应在vue项目之中则是apis.js中提供api,对应在django项目之中的则是urls.py定义的path,事实上,我们在api.js之中去调用django之中定义好的path,直接进行调用,此处往往是利用axios的ajax方法进行调用,此处是我的api.js为例:
import axiosInstance from './index'
const axios = axiosInstance
export const proxy = 'http://192.168.56.138:8000/'
export const getUserInfos = () => {return axios.get(proxy+ `userInfo/`)}
export const login = (name,password) => {return axios.post(proxy+ `login`, {'name': name, 'password': password})}
export const getUserInfo = () => {return axios.get(proxy + `getUserInfo`)}
export const logout = () => {return axios.get(proxy + `logout`)}
这组api十分类似于java中interface,规定了前后端的编程规范,后端负责实现,前端负责调用
第一个登陆界面
基本目标:在前端网页输入用户名密码,点击提交后,如果密码正确,跳转指定页面,否则跳转错误提示页面
实现思路:
- 前端利用vue页面编写一个input模块给用户输入用户名和密码
- 在按钮点击提交时,将用户名以及密码封装进一个POST请求之中,发给后台
- 后台根据用户名查询对于密码,并验证POST之中的密码是否与之相符
- 根据不同的情况,分别返回不同的路由
- 前端的回调函数处理不同路由,跳转不同页面
具体如下
编写一个登陆模块的vue,需要axios模块提供对于get和post方法的支持,在通用模块文件夹下,例如axios实例代码如下:
import Vue from 'vue'
import Axios from 'axios'
const axiosInstance = Axios.create({
withCredentials: true
})
// 通过拦截器处理csrf问题,这里的正则和匹配下标可能需要根据实际情况小改动
axiosInstance.interceptors.request.use((config) => {
config.headers['X-Requested-With'] = 'XMLHttpRequest'
const regex = /.*csrftoken=([^;.]*).*$/
config.headers['X-CSRFToken'] = document.cookie.match(regex) === null ? null : document.cookie.match(regex)[1]
return config
})
axiosInstance.interceptors.response.use(
response => {
return response
},
error => {
return Promise.reject(error)
}
)
Vue.prototype.axios = axiosInstance
export default axiosInstance
随后我们在login.vue之中去调用apis.js之中的login的ajax方法:
// eslint-disable-next-line no-unused-vars
import {getUserInfos,login,proxy} from '@/api/api'
export default {
name: 'HelloWorld',
data () {
return {//此处使用v-model来获取输入
inputUser: {
"name": "",
"password": "",
}
}
},
methods: {
login () {//这个login是vue之中定义的方法login
//这个是调用的apis.js之中的login方法,需要传入两个实参,将其封装进请求的body之中
login(this.inputUser.name, this.inputUser.password).then(response => {
//这里是ajax的成功后的回调函数,此处我们让vue重定向
this.$router.replace('/userInfo')//重定向
})
}
},
}
</script>
其中router使用的是vue-router,注意启用vue-router一定要在vue之中加上
<router-view></router-view>
配置方法如下:vue-router安装和使用指南
vue-router负责处理是一定是上文提到的B1的端口的请求,django中的urls.py处理的是B2端口的,对应到我项目之中就是vue-router处理nginx监听的80端口,而django处理的是8000端口。部署成功后我们可以通过http://192.168.56.138/,即80端口来访问vue项目首页。
同时为了实现有状态的https我们还需要引入vue-cookies,vue-cookies部署以及使用
我们在登出时通过删除cookies来消除状态,同后端一样,只有先实现跨域了,cookies才会前后端保持一致。
this.$cookies.remove('username');
this.$cookies.set('token',0)
至此前端功能的逻辑已经基本完整。
Element-UI
进入项目根目录
npm i element-ui -S
随后在main.js之中加入,即可进行调用
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
组件使用方法参加官网Element-UI
在vue之中的编写关联和一般的DOM语法一致,通过class进行关联css
vue跨域解决方案
首先遇到了一个比较奇怪的问题,部署在django后端相同的虚拟机的前端项目可以正常获取后端设置cookie,而部署在本地则不可以,并且在chrome了可以看到一个小感叹号,同时在pycharm之中可以看到request之中cookie是有的,并且chrome之中的response之中的set-cookie也是可以看见的,所以根据以上信息基本确定是vue跨域设置不正常导致cookie不可用。
配置vue代理服务器
//vue.config.js
proxy: { // 配置跨域
'/': {
target: 'http://192.168.56.138:8000', //接口域名
ws: true, //是否代理websockets
changOrigin: true, //是否跨域
secure:false,
// pathRewrite:{
// '^/api':'',
// }
}
},
//apis.js
export const proxy = '/'
一定要将apis.js里的接口设置成代理服务器的名字。通过伪造请求使得http请求为同源的,然后将同源的请求发送到反向代理服务器上,由反向代理服务器去请求真正的url,这样就绕过直接请求真正的url导致跨域问题。
未配置代理的,两者request URL上是有明显区别的。
当用户在浏览器上点击一个链接时,会产生一个 HTTP 请求,用于获取新的页面内容,而在该请求的报头中,会包含一个 Referrer,用以指定该请求是从哪个页面跳转页来的,常被用于分析用户来源等信息。但是也有成为用户的一个不安全因素,比如有些网站直接将 sessionid 或是 token 放在地址栏里传递的,会原样不动地当作 Referrer 报头的内容传递给第三方网站。
所以就有了 Referrer Policy,用于过滤 Referrer 报头内容,目前是一个候选标准,不过已经有部分浏览器支持该标准。具体的可查看这里。
Referrer Policy详解