一、Vue-cli的环境准备
目的:(1)快速管理依赖 (2)确定项目结构
1.安装node.js
Node.js是一个可以让前端运行在服务器上的一个工。
测试node.js是否安装成功:cmd下输入node -v
npm config set prefix F:\node\node_global npm config set cache F:\node\node_cache
2. 使用npm安装vue-cli
npm install -g @vue/cli 3.x npm install –g vue-cli 2.x npm: node.js包管理工具 install: 安装 vue-cli:要安装的工具 -g:全局安装
3. 配置使用国内源
npm配置国内镜像
npm config set registry https://registry.npm.taobao.org npm config set disturl https://npm.taobao.org/dist npm config set electron_mirror https://npm.taobao.org/mirrors/electron/
npm查看当前镜像
npm config get registry
yarn配置国内镜像
yarn config set registry https://registry.npm.taobao.org yarn config set disturl https://npm.taobao.org/dist yarn config set electron_mirror https://npm.taobao.org/mirrors/electron/
yarn查看当前镜像
yarn get registry
二、使用vue-cli下载项目骨架搭建项目
- vue create 项目名称
- 安装项目依赖 npm install
注:3.x版本之后创建项目时就会自动安装
-
使用开发模式运行项目
npm run dev 2.x
npm run serve 3.x
此时可以在浏览器中:http://localhost:8080 访问首页
三、Vue组件的组成部分
.1. vue文件的组成部分
2.在vue组件中使用多个vue组件搭建一个页面
- 全局注册
import Vue from 'vue'
import App from './App.vue'
import Header from "./components/Header";
import Content from "./components/Content";
import Footer from "./components/Footer";
Vue.component('MyHeader', Header);
Vue.component('MyContent', Content);
Vue.component('MyFooter', Footer);
Vue.config.productionTip = false;
new Vue({
render: h => h(App),
}).$mount('#app');
- 本地注册
在组件的内部注册另外一个组件,成为一个标签,这个标签只在该组件内部使用,而不能在其他组件内部使用。
<template>
<div >
<MyHeader></MyHeader>
<MyContent></MyContent>
<MyFooter></MyFooter>
</div>
</template>
<script>
import Header from "./components/Header";
import Content from "./components/Content";
import Footer from "./components/Footer";
export default {
name: 'App',
components: {
'MyHeader': Header,
'MyContent': Content,
'MyFooter': Footer,
}
}
</script>
四、Vue组件之间的参数传递
- 父传子
App.vue
<template>
<div >
<MyHeader></MyHeader>
<MyContent :Mytitle="title"></MyContent>
<MyFooter></MyFooter>
</div>
</template>
export default {
name: 'App',
components: {
'MyHeader': Header,
'MyContent': Content,
'MyFooter': Footer,
},
data(){
return {
title: "Hello Vue!"
}
}
}
content.vue
<template>
<div>
<h2>{{Mytitle}}</h2>
商品列表...
</div>
</template>
<script>
export default {
name: "Content",
props: ['Mytitle',]
}
</script>
通过子组件的props属性,来指明可以接收的参数,父组件通过在标签中写明参数的键值对来传递参数。
props表示一个组件的参数部分,有两种写法:
(1)props:[参数列表]
比如:props:[‘MyProp1’,’MyProp2’]
(2)props:[参数名1:{type:String,required:true,default:”xx”},参数名2:{}]
- 子传父
App.vue
<template>
<div >
<MyHeader></MyHeader>
<MyContent :Mytitle="msg" :btnfn="change_msg"></MyContent>
<MyFooter></MyFooter>
</div>
</template>
<script>
import Header from "./components/Header";
import Content from "./components/Content";
import Footer from "./components/Footer";
export default {
name: 'App',
components: {
'MyHeader': Header,
'MyContent': Content,
'MyFooter': Footer,
},
data(){
return {
msg: "Hello Vue!"
}
},
methods:{
change_msg(v){
this.msg = v;
}
}
}
</script>
content.vue
<template>
<div>
<h2>{{Mytitle}}</h2>
商品列表...
<button type="button" @click="btnfn('hello python')">点我</button>
</div>
</template>
<script>
export default {
name: "Content",
// props: ['Mytitle',]
props:{
'Mytitle':{
type:String,
required: true,
default: "xx",
},
'btnfn': {
type: Function,
}
}
}
</script>
- 以事件发射的方式子传父
子组件中,使用this.$emit(‘键', ‘值’)
父组件中,在子组件标签中使用@键=”msg=$event”
Content.vue
doClick(){
this.$emit("newName", "hello js");
}
}
App.vue
<MyContent :Mytitle="msg" @newName="msg=$event"></MyContent>
五、Vue使用Axios
- 安装axios
npm install --save axios vue-axios
- 在main.js使用axios
import Vue from 'vue' import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios, axios) 或 import Vue from 'vue' import axios from 'axios' Vue.prototype.axios = axios
1. get请求
方式一
this.axios({
method:'get',
url:'http://127.0.0.1:8000/register',
params:{
"mail": this.mail,
"password": this.password,
},
}).then(function (response) {
console.log(response.data);
});
方式二
const { data: res, status: status } = await this.axios.get('users/getUserList', {
params: this.queryInfo
});
if (status !== 200) {
return this.$message.error('获取用户列表失败!')
}
this.userlist = res.data.users;
this.total = res.data.total
2. post请求
发送post请求: 解决axios无法传递data中的参数问题
默认情况下发送axios时请求头中的内容类型为:
Content-Type:application/json;charset=UTF-8
而如果服务端需要的是:
Content-Type:application/x-www-form-urlencoded
因此,使用axios的qs内置库中的方法进行内容类型的转换。
import Qs from 'qs'
this.axios({
method:'post',
url:'http://localhost:8081/regist',
transformRequest: [function (data) {
return Qs.stringify(data)
}],
data:{
email:this.email
}
}).then(function (response) {
alert(response.data.message)
})
方式二
const { data: res, status: status } = await this.axios.post('users/addOneUser', user_form);
if (status !== 200) {
this.$message.error('添加用户失败!')
}
this.$message.success('添加用户成功!')
this.UserDialogVisible = false;
this.getUserList()
3.pu
const { data: res, status: status } = await this.axios.put('users/updateUser', user_form);
if (status !== 200) {
this.$message.error('更新用户信息失败!')
}
// 隐藏添加用户对话框
this.UserDialogVisible = false;
this.$message.success('更新用户信息成功!')
this.getUserList()
4.delete
const { data: res, status: status } = await this.axios.delete('users/deleteUser', {
params:{"id": id},
});
if (status !== 200) return this.$message.error('删除用户失败!')
this.$message.success('删除用户成功!');
this.getUserList()
5. axios拦截器
axios.interceptors.request.use(config => {
NProgress.start()
config.headers.Authorization = Storage.sessionGet("token");
return config
})
axios.interceptors.response.use( response => {
NProgress.done()
if (response.status >= 250 && response.status <= 260) {
Storage.sessionRemove('token') // 删除已经失效或过期的token(不删除也可以,因为登录后覆盖)
router.replace({path: '/Login'}).catch(err => {err})
} else if (response.data.token) {
Storage.sessionSet('token', response.data.token)
}
return response
})
六、解决跨域请求问题
1) 什么是跨域?
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。
所谓同源是指,域名,协议,端口均相同,只要有一个不同,就是跨域。不明白没关系,举个栗子:
http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域) http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域) http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域) http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域) http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域) 请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。
2)为何要研究跨域问题?
因为浏览器的同源策略规定某域下的客户端在没明确授权的情况下,不能读写另一个域的资源。而在实际开发中,前后端常常是相互分离的,并且前后端的项目部署也常常不在一个服务器内或者在一个服务器的不同端口下。前端想要获取后端的数据,就必须发起请求,如果不做一些处理,就会受到浏览器同源策略的约束。后端可以收到请求并返回数据,但是前端无法收到数据。
3)为何浏览器会制定同源策略
之所以有同源策略,其中一个重要原因就是对cookie的保护。cookie 中存着sessionID 。黑客一旦获取了sessionID,并且在有效期内,就可以登录。当我们访问了一个恶意网站 如果没有同源策略 那么这个网站就能通过js 访问document.cookie 得到用户关于的各个网站的sessionID 其中可能有银行网站 等等。通过已经建立好的session连接进行攻击,比如CSRF攻击。这里需要服务端配合再举个例子,现在我扮演坏人 我通过一个iframe 加载某宝的登录页面 等傻傻的用户登录我的网站的时候 我就把这个页面弹出 用户一看 阿里唉大公司 肯定安全 就屁颠屁颠的输入了密码 注意 如果没有同源策略 我这个恶意网站就能通过dom操作获取到用户输入的值 从而控制该账户所以同源策略是绝对必要的.还有需要注意的是同源策略无法完全防御CSRF。
4)跨域会阻止什么操作?
浏览器是从两个方面去做这个同源策略的,一是针对接口的请求,二是针对Dom的查询
5)多种跨域方法
跨域可以大概分为两种目的
前后端分离时,前端为了获取后端数据而跨域
为不同域下的前端页面通信而跨域
为前后端分离而跨域
ü Cross Origin Resource Share (CORS)
CORS是一个跨域资源共享方案,为了解决跨域问题,通过增加一系列请求头和响应头,规范安全地进行跨站数据传输。CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否.通过过滤器在response中返回头部,使服务器和浏览器可互通。
Access-Control-Allow-Origin:指定授权访问的域
Access-Control-Allow-Methods:授权请求的方法(GET, POST, PUT, DELETE,OPTIONS等)
适合设置单一的(或全部)授权访问域,所有配置都是固定的,特简单。也没根据请求的类型做不同的处理
func Cors() gin.HandlerFunc { return func(c *gin.Context) { method := c.Request.Method c.Header("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token") c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") //服务器支持的所有跨域请求的方 c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type") c.Header("Access-Control-Allow-Credentials", "true") //放行所有OPTIONS方法 if method == "OPTIONS" { c.AbortWithStatus(http.StatusNoContent) } // 处理请求 c.Next() } } func main() { r := gin.Default() r.Use(Cors(),) r.GET("/register", RegisterHandler) _ = r.Run(":8000") }