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获取所有的键值对