1.Vue简介
是一套用于构建用户界面的渐进式框架,自底层向上应用,Vue的核心库只关注视图层,容易入门,可以和第三方库或者已有的项目进行整合,可以做复杂的单页应用。 简单的说,vue是一套前端的开发框架,vue是目前三大主流的框架之一,其他两个框架是:React、Angular。
(1)注意:前后端分离时会报错: Access-Control-Allow-Origin 跨域问题
跨域的概念:后台服务为了保护自己的接口,将不是同一种请求方式,以及不同一个IP,以及不是同端口号的,拒绝访问;
解决方法:
1.后台来解决 : 后台接口添加@CrossOrigin注解
2.前台来解决
在前台项目的config中的index.js中的proxyTable中加入配置,并修改main.js的路径为"/api"
//前端页面进行跨域解决。注意,使用这种方式,只能在有Nodejs的服务中跨域成功
//跨域发生在不同的进程之间,但是后端的服务之间是没有跨域问题得,例如springboot mysql 没有跨域问题,所以第二种解决跨域的
//方案为,将请求交给nodejs(后端的服务),由Nodejs进行请求的转发
//该方案只能本地模式下使用,在部署了前端页面后,是无法使用的
proxyTable: {
'/api': {
target: 'http://localhost:8080/', // 设置你调用的接口域名和端口号
changeOrigin: true, // 跨域
pathRewrite: {
'^/api': '/'
}
},
},
3.使用nginx来解决
在nginx的配置文件里完成配置,并在前台项目中修改路径
修改前台项目路径为axios.defaults.baseURL="http://localhost:7000/";
#跨域问题的解决
server {
#监听端口号7000
listen 7000;
server_name localhost;
location / {
#注意跨域只需要解决一次。后台的@CrossOrigin 和下方的跨域解决方案,两者选其一,进行解决
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'POST, GET, OPTIONS, DELETE, PUT';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,token';
#跨域OPTIONS请求,set response header后直接204返回
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#转发的服务器的ip地址以及端口号
proxy_pass http://edu;
}
}
(2)项目优化,全局使用axios
在main.js中配置
1.下载axios
npm install axios
2.统一管理axios
import axios from 'axios';
3.设置全局使用axios
Vue.prototype.$axios=axios;
4.设置axios请求的默认的ip以及端口号
axios.defaults.baseURL="http://localhost:8080"
2.Vue基本使用概念
(1)Vue基本使用步骤
<1>导入开发版的Vue.js
<2>创建Vue实例对象,设置el属性和data属性
<3>使用简介的模板语法把数据渲染到页面上
(2)el: 挂载点
Vue会管理el选项命中的元素及其内部的后代元素,可以使用其他的选择器,但是建议使用id选择器,可以使用其他双标签,但是不能使用HTML和BODY.
(3)data: 数据对象
Vue中用到的数据定义到data中,data中可写复杂类型的数据,渲染复杂类型数据遵守js的语法即可.
(4)methods:{} : 书写方法
(5)mounted(){this.findAll() }; 和methods同级,类似于$(function),相当于页面载入事件
eg:什么时候触发findAll() ,页面加载的时候,触发这个方法:vue的页面载入事件
3.Vue的基本指令
(1)v-text : 设置标签的文本值
v-text指令的作用是:设置标签的内容<textContent>,默认写法会替换全部内容,使用差值表达式可以替换指定内容;内部支持写表达式.
(2)v-html : 设置标签的innerHTML属性
v-html指令的作用是设置元素的innerHTML属性,内容中有html结构会被解析为标签,v-text指令无论内容是什么,只会解析为文本,解析文本使用v-text,需要解析html结构使用v-html
(3)v-on : 为元素绑定事件
v-on指令的作用是为元素绑定事件,事件名不需要写on,指令可以简写为@,绑定的方法定义在methods属性中,方法内部通过this关键字可以访问定义在data中的数据.
(4)v-show : 根据表达式的真假切换元素的显示与隐藏
v-show指令的作用是根据真假切换元素的显示状态,原理是修改元素的display,实现显示隐藏,指令后面的内容,最终都会解析为布尔值,值为true元素显示,值为false元素隐藏,数据改变之后,对应元素的显示状态会同步更新.
(5)v-if : 根据表达式的真假,切换元素的显示和隐藏,操纵dom元素
v-if指令的作用是根据表达式的真假切换元素的显示状态,本质是通过操纵dom元素来切换显示状态,表达式值为true,元素存在于dom树种,值为false,从dom树中移除,频繁的切换使用v-show,反之使用v-if,前者的切换消耗小.
(6)v-bind : 设置元素的属性,例如src,title等
v-bind指令的作用是为元素绑定属性,完整的写法是 v-bind:属性名,简写可以省略v-bind,只保留 :属性名,需要动态的增删class建议使用对象的方式
(7)v-for : 遍历使用,根据数据生成列表结构
v-sfor指令作用是根据数据生成列表结构,数组经常和v-for结合使用,语法是 (item,index) in 数据;item和index可以结合其他指令一起使用,数组长度的更新会同步到页面上,是响应式的.
(8)v-model : 获取和设置表单元素的值,为双向数据绑定
v-model指令的作用是便捷的设置和获取表单元素的值,绑定的数据会和表单元素值相关联,一边改变另一边也会随之改变.
3.2Vue的监听属性watch
可以通过 watch 来响应数据的变化
handler:watch中需要具体执行的方法
deep:需要监听的数据的深度,一般用来监听对象中某个属性的变化,数组字符串一般不需要
immediate:在选项参数中指定immediate:true将立即以表达式的当前值触发回调
data(){
return{
counter: 1
}
},
watch:{
'counter':{
handler(newVal,oldVal){
alert('计数器变化:'+oldVal+'变为了'+newVal+'!!')
},
deep:true,
immediate:true
}
}
3.3Vue计算属性 reversedMessage
提供的函数将用作属性 vm.reversedMessage 的 getter 。
vm.reversedMessage 依赖于 vm.message,在 vm.message 发生改变时,vm.reversedMessage 也会更新。
我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。 而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
可以说使用 computed 性能会更好,但是如果你不希望缓存,你可以使用 methods 属性。
<p>原始字符串: {{message}}</p>
<p>反转后字符串: {{reversedMessage}}</p>
computed:{
//计算属性的 getter
reversedMessage:function (){
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
3.3label组件
点击label标签后会出现和点击button按钮一样的效果:label中for的值是服务元素的id值,简单来说就是,绑定指定id的元素,点击label后会激活相应的控件.
<input type="checkbox" id="google" value="Google" v-model="checkedNames">
<label for="google">Google</label>
3.4组件
组件和页面文件中内容是完全相同的,唯一的区别是组件可能被多次使用,import 时会给组件定义个名称,而页面文件可能只使用一次,import 时就不需要定义名称。 在项目中为了区分页面和组件,把组件放在 components 文件夹下,而页面则放在 pages 或 views 文件夹下。
(1)全局组件
所有实例都能用全局组件(参数1为组件名称)
Vue.component("count",{
template:'<li>this is a todo</li>'
})
4.Vue的使用
(1)cdn方式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
//引入vue的js
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<body>
<div id="app">
{{message}}
</div>
</body>
<script>
new Vue({
代表vue所接管的区域,里边是区域的id值
el:'#app',
数据绑定
data:{
message: "hello word111",
},
声明执行的方法
methods:{
sub:function(){}
},
mounted(){} 相当于页面载入事件
})
</script>
</html>
(2)使用vue-cli方式
创建项目:vue init webpack firstVue
<1>简单入门,页面跳转
1.在components目录下创建vue
<template>
<div>
<h1>{{msg}}</h1>
</div>
</template>
<script>
export default {
name: "index",
data(){
return{
msg:"欢迎来到首页"
}
}
}
</script>
<!-- 该页面的样式-->
<style scoped>
</style>
2.在router目录下配置路由
import Vue from 'vue' //引入了vue
import Router from 'vue-router' //引入了vue-router
//将页面导入到index.js中,使用路由来去确定访问该页面的路径
//引入项目下的index组件
import index from '@/components/index'
//配置路由
export default new Router({
routes: [
//配置路由这里是一个数组,每一个链接都是一个对象
{
//访问的路径 / 默认为首页
path:'/',
//页面的名称,我们跳转是使用name 进行跳转,而不使用路径跳转,因为路径可以修改,只要name 不做修改,就可以正常工作
name:'index',
//页面的资源,组件名称,必须与导入组件名称一致
component:index
}
]
})
3.在父页面App.vu中使用router-link制作导航跳转到该页面
<router-link to="/">首页</router-link><br/>
<2>父子路由
1.编写fu,zi1,zi2页面
<template>
<div>
<h1>这是终极父页面的儿子Hi,我的儿子有Hi1和Hi2</h1><br/>
<!-- 当前子页面的加载的位置-->
<router-view></router-view>
</div>
</template>
2.配置路由
import Hi from '@/components/Hi'
import Hi1 from '@/components/Hi1'
import Hi2 from '@/components/Hi2'
{
path:'/hi',
name:'hi',
component:Hi,
children: [
{path:'hi1',name:'hi1',component:Hi1},
{path:'hi2',name:'hi2',component:Hi2}
]
}
3.在终极父页面制作导航跳转
<router-link to="/hi">hi页面</router-link><br/>
<router-link to="/hi/hi1">hi1页面</router-link><br/>
<router-link to="/hi/hi2">hi2页面</router-link><br/>
<3>左右页面展示
1.编写主页面,左页面,右页面
<template>
<div>
<h1>这是主页面</h1>
<!--主页面展示的位置-->
<router-view></router-view>
</div>
</template>
2.路由配置
import mainPage from '@/components/mainPage'
import leftPage from '@/components/leftPage'
import rightPage from '@/components/rightPage'
{
path:'/mainPage',
name:'mainPage',
components:{
default:mainPage, //默认的页面
left:leftPage, //左边的页面 left 是<router-view name="left"
right:rightPage //右边的页面 right 是<router-view name="right"
}
}
3.终极父页面制作导航跳转
<router-link to="/mainPage">去到主页面</router-link>
<!-- 加载子页面-->
<router-view/>
<!-- 单页面多路由的操作-->
<router-view name="left" style="float: left;width: 50%;background-color: #42b983"></router-view>
<router-view name="right" style="float: left;width: 50%;background-color:lavender"></router-view>
<4>重定向
<template>
<div>
<router-link to="/goback">回到首页</router-link>
</div>
</template>
//重定向
{
path:'/goback',
redirect:'/'
}
<5>错误页面处理
1.编写页面
<template>
<div>
<h1>走丢了?回到首页</h1>
<router-link to="/goback">回到首页</router-link>
</div>
</template>
2.配置路由
//404页面处理
{
path:'*',
component:error
}
5.路由传参
(1)方式1:通过路由中的name值来进行传参,使用较少,没有实际应用的方便
1.编写页面
<template>
<div>
<h1>这是参数页面</h1>
通过Name获取到的参数为:{{$route.name}}<br>
</div>
</template>
2.路由配置
{
path:'/parm1',
name:'parm',
component:parm1
}
3.制作页面导航
<router-link to="/parm1">name传参页面</router-link><br/>
<2>通过to标签传参
1.编写页面
<template>
<div>
<h1>这是参数页面</h1>
:to是v-bind:to的缩写
通过:to获取到的参数为:{{$route.params.id}}
</div>
</template>
2.配置路由
{
path:'/parm1',
name:'parm1',
component:parm1
}
3.制作导航
<router-link :to="{name:'parm1',params:{id:'1'}}">to标签传参</router-link>
<3>通过url路径进行传参
1.编写页面
<template>
<div>
<h1>这是url参数页面</h1>
通过url获取到的参数为:{{$route.params.id}}<br>
通过url获取到的参数为:{{$route.params.name}}<br>
</div>
</template>
2.配置路由
{
path:'/parm2/:id/:name',
name:'parm2',
component:parm2
}
3.制作导航
<router-link to="/parm2/1/张三">url路径传参</router-link>
注意事项:
配置index.js 在path路径后跟上:key值,可以一次性传递多个参数;
通过url传递参数时,必须路径上有该参数,如果没有,则无法访问到对应的页面;
在对应页面中通过{{$route.parmas.key}}获取
<4>编程式导航 :通过点击触发方法,在方法中进行参数的传递
1.编写页面并获取
通过编程式导航获取到的参数为:{{$route.params.name}}
<button v-on:click="fun">编程式导航</button>
methods:{
fun:function () {
//进行页面的跳转同时,携带参数
this.$router.push({name:"parm3",params:{name:"李四"}})
}
}
2.路由配置
import index from '@/components/index'
import parm3 from '@/components/parms/parm3'
{
path:'/parm3',
name:'parm3',
component:parm3
}
注意事项:
通过触发方法,进行参数的传递;
传递格式:this.$router.push({name:'跳转页面的name',params:{key:value}})
接收格式:在对应页面通过{{$route.params.key}}获取参数
6.axios的使用
(1)方式1:
deleteById:function (id) {
var _this = this;
axios.get("/product/deleteById?id="+id).then(function (res) {
_this.findAll()
window.localStorage.setItem("pid",id);
window.location.href="update.html"
})
}
(2)方式2:
methods:{
sub:function () {
this.$axios.post("http://localhost:8080/product/updateOrSave",this.product).
then(res=>{
this.$router.push("/")
})
}
}
7.nginx
(1)反向代理: nginx将监听到的请求转发到对应的服务器中
#反向代理服务器
#server{
#监听端口号7000
#listen 7000;
#server_name localhost;
#location /{
#转发的服务器的ip地址以及端口号
#proxy_pass http://localhost:8080/;
#proxy_pass http://edu;
#}
#}
(2)负载均衡: 基于反向代理,当进行请求转发时有多台服务,可以根据配置进行不同规则转发,意思是将请求分到多个服务单元上执行,能有效解决高并发问题.
#配置负载均衡的服务器列表
upstream edu{
#配置当前要转发的服务列表 server ip:port;
#1.均衡的默认规则为 轮询RR 的规则:配置在服务器的硬件以及网卡都一致的情况下,平均分配请求
#server localhost:8080;
#server localhost:8081;
#2.负载均衡的策略:权重的规则,根据服务的硬件不同,硬件越好的服务器,处理能力越强,我们可以将更多的请求转发到该服务器
#weight 代表请求到该服务的权重 它是百分比
#server localhost:8080 weight=9;
#server localhost:8080 weight=1;
#3.负载均衡的策略:ip_hash策略,解决session失效问题
#根据当前请求得ip值,计算出HASH码,把当前HASH码与某一个服务匹配,该IP未来访问的所有的接口,都是与匹配了的服务进行交互。
ip_hash;
server localhost:8080;
#server localhost:8081;
}
(3)搭建web服务器,部署前端项目
将前端项目build完成后,将生成的dist文件下的static和index.html放在nginx的html目录下即可.
(4)静态服务器的搭建
#静态服务器的搭建
#通常用户静态资源的网络访问,例如图片,将图片存储到该路径下,则nginx会将该图片提供网络的访问
server{
listen 8888;
server_name localhost;
#将计算机下的某个盘符,作为静态资源服务器
location /file/{
root E:/QLDownload/;
autoindex on;
}
}
8.redis
(1)存储方式
<1>string类型设置,常用于存储验证码信息
1.向redis种设置 key 值
redisTemplate.opsForValue().set("name","张三");
2.从redis获取值
Object name = redisTemplate.opsForValue().get("name");
3.设置当前key的存活时间
redisTemplate.expire("name",20, TimeUnit.SECONDS);
<2>list类型设置
注意:redis中的 list 是双向的,所以添加的时候需要注意,rightPush先进先出;leftPush先进后出
1.添加
<--leftPushAll 从头部添加-->
redisTemplate.opsForList().leftPushAll("list1",list);
<--rightPushAll 从尾部添加-->
redisTemplate.opsForList().rightPushAll("list1",list);
2.从redis种获取 1.key值。2.起始下标的位置。3.结束下标的位置,如果获取全部 0,-1
List list1 = redisTemplate.opsForList().range("list1", 0, -1);
<3>set集合,无序且不可重复的集合
1.向set种设置值
redisTemplate.opsForSet().add("st1","1","1","2","3","4","5");
2.从Redis中获取到set的无序且不可重复的集合
Set st1 = redisTemplate.opsForSet().members("st1");
<4>zset集合,有序且不可重复,常用于一些排行榜的实现等
1.zset集合是有序的,通过最后的一个为double的属性进行排序,可理解为score分数
redisTemplate.opsForZSet().add("zst1","张三",10);
redisTemplate.opsForZSet().add("zst1","李四",1);
redisTemplate.opsForZSet().add("zst1","王五",2);
2.从zst1种获取有序集合根据score从小到大的排序
Set zst1 = redisTemplate.opsForZSet().range("zst1", 0, -1);
3.从zst1获取,有序集合根据score从大到小的排序
Set zst11 = redisTemplate.opsForZSet().reverseRange("zst1", 0, -1);
<5>hash结构,其他结构不同的是,hash有两层key值,第一层key是redis的key,第二层key是自己设置的key值,想要获取一条数据,需要两个key值进行获取
1.向redis种放置hash结构的数据 (1)redis的key(2)数据的Key(3)数据内容
redisTemplate.opsForHash().put("hm1","name","张三");
redisTemplate.opsForHash().put("hm1","age","18");
2.获取:通过两层key获取到具体的一个value值
Object o = redisTemplate.opsForHash().get("hm1", "name");
Map hm1 = redisTemplate.opsForHash().entries("hm1"); 通过redis的key获取所有的键值对