Vue

Vue

一、Vue概述

(一)Vue是什么

Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架。Vue 只关注视图层, 采用自底向上增量开发的设计。
Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
Vue.JS是优秀的前端 JavaScript 框架

image

(二)为什么学习Vue

随着项目业务场景的复杂,传统模式(html+jquery)已无法满足需求,就出现了Angular/React/Vue等框架
企业需求、主流框架之一、易用、灵活、高效

(三)Vue能做什么

最大程度上解放了 DOM 操作
单页web项目开发
传统网站开发

什么是工具(库)、什么是框架

1.库(插件):是一种封装好的特定方法集合,对项目的侵入性较小,提供给开发者使用,控制权在使用者手中,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求 (jquery)

2.框架:是一套架构,会基于自身特点向用户提供一套相当完整的解决方案,而且控制权在框架本身;对项目的侵入性较大,使用者要按照框架所规定的某种特定规范进行开发,项目如果需要更换框架,则需要重新架构整个项目

二、Vue核心特征

① 解耦视图与数据
② M-V-VM模型 关注模型和视图
M:即Model,模型,包括数据和一些基本操作。
V:即View,视图,页面渲染结果
VM:即View-Model,模型和视图间的双向操作
③ 双向数据绑定

(一)MVVM之前

开发人员从后端获取需要的数据模型,然后要通过DOM操作Model渲染到View中。而后当用户操作视图,我们还需要通过DOM获取View中的数据,然后同步到Model中

(二)MVVM之后

而MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发人员不用再关心Model和View之间是如何互相影响的:

  • 只要我们Model发生了改变,View上自然就会表现出来。
  • 当用户修改了View,Model中的数据也会跟着改变
    把开发人员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model上

image

三、Vue入门

(一)下载安装

vue是一个前端框架,也是其实是一个js文件,下载vue.js文件并在页面中引入
vue.js的下载方式:
① 可以引入在线的vue.js(公共的CDN服务)
	<!-- 开发环境版本,包含了用帮助的命令行警告 -->
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	或
	<!-- 生产环境版本,优化了尺寸和速度 -->
	<script src="https://cdn.jsdelivr.net/npm/vue"></script>
② 可以离线下载vue.js
	开发版本: https://vuejs.org/js/vue.js
	生产版本: https://vuejs.org/js/vue.min.js

③ npm包资源管理器,可以下载vue.js  (前端专用)
	初始化:npm init -y
	安装vue:npm install vue --save
	注:切记重启计算机

(二)第一个vue

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
     <div id="app">
         <h2>{{name}},欢迎你!</h2>
     </div>
     <script src="https://cdn.jsdelivr.net/npm/vue"></script>
     <script type="text/javascript">
         //生成一个Vue实例
         var app=new Vue({
             el:"#app",//el ,即是element。要渲染的页面元素
             data:{//数据
                 name:"优就业"
             }
         })
     </script>
</body>
</html>

Vue参数详解:
	1. body中,设置Vue管理的视图<div id="app"></div> 
	2. 引入vue.js
	3. 实例化Vue对象 new Vue();
	4. 设置Vue实例的选项:如el、data...
		new Vue({选项:值});
	5. 在<div id='app'></div>中通过{{ }}使用data中的数据

四、Vue常见指令

指令 (Directives) 是带有 v- 前缀的特殊attribute。是Vue框架提供的语法,扩展了html标签的功能、大部分的指令的值是js的表达式。用于取代DOM操作

(一)v-textv-html

类似innerText和innerHTML
	① v-text:更新标签中的内容
	② v-html:更新标签中的内容/标签
案例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-text、v-html</title>
    <script src="js/vue.js"></script>
</head>
<body>
    
    <div id="app">
        <!-- 
            插值表达式  {{}}
            v-text  不识别html文本们只能原样输出,直接覆盖原本标签的内容
            v-html  能识别html文本,直接覆盖原本标签的内容
        -->
            <p v-text="a">您好</p>
            <p v-html="b"></p>
            <p v-html="c"></p>
            <p>你好,{{msg}}</p>
    </div>
</body>
<script>

    let app =  new Vue({
        el:"#app",
        data:{
            msg:"helloworld",
            a:'hi',
            b:'hello',
            c:'<h1>嗨</h1>'
        }
    });
</script>
</html>

(二)v-ifv-show

根据表达式的boolean值进行判断是否渲染该元素
案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="vue.js"></script>
</head>
<body>
    <!-- v-if  v-show 都可以用于显示或者隐藏元素 
        区别:
            v-if 使用注释 隐藏元素
            v-show 使用样式 display:none 隐藏元素
    -->
    <div id="app">
        <p v-if="show">{{name}}</p>
        <p v-show="show">{{name}}</p>
    </div>
</body>

<script>
    let app = new Vue({
        el:"#app",
        data:{
            name:'张三',
            show:true
        }
    })
</script>
</html>

(三)v-on

① 作用:使用 v-on 指令绑定 DOM 事件,并在事件被触发时执行一些 JavaScript 代码。
② 语法:
	 v-on:事件名.修饰符 = "methods中的方法名";
	 v-on的简写方法: @事件名.修饰符 = "methods中的方法名";
③ 案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-on</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <div id="app">
        <p>当前计数: {{count}}</p>
        <!-- <button type="button" v-on:click="jia()">+</button>
        <button type="button" v-on:click="jian()">-</button> -->

        <!-- <button type="button" @click="jia()">+</button>
        <button type="button" @click="jian()">-</button> -->


        <button type="button" @click="count++">+</button>
        <button type="button" @click="count--">-</button>
    </div>
</body>

<script>

    let app =  new Vue({
       el:"#app",
       data:{
            count:0
       },
       methods:{
            jia(){
                this.count++;
            },
            jian(){
                this.count--;
            }
       }
    });
</script>
</html>

v-on绑定事件案例:

image

练习-显示隐藏

内容显示时,按钮是隐藏功能。隐藏内容后,按钮是显示功能,显示、隐藏共用一个按钮.

image

image

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-on</title>
    <script src="vue.js"></script>
</head>
<body>
        <div id="app">
                <p v-show="condition">你能看见我吗</p>
                <button @click="change()">{{btn}}</button>
        </div>

        
</body>
<script>
    let app = new Vue({
        el:"#app",
        data:{
            btn:'隐藏',
            condition:true
        },
        methods:{
            change(){
               this.btn =  this.btn=="隐藏" ?"显示":"隐藏";
               this.condition = this.btn=="隐藏"?true:false;
            }
        }
        
    })
</script>
</html>

(四)v-for

① 作用:列表渲染,当遇到相似的标签结构时,就用v-for去渲染
② 格式:
	    (item,index) in 数组或集合 
	 	参数item:数组中的每个元素 
	 	参数index:数组中元素的下标

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-for</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- 
            遍历固定次数、固定内容
            <p v-for="(item, index) in 100">好好学习,天天向上</p>
         -->


         <!-- 遍历数组-->
         <p v-for="(stu, index) in stuArr">{{index}}--{{stu.name}}--{{stu.age}}</p>
    </div>
</body>

<script>

    let app =  new Vue({
       el:"#app",
        data:{
            stuArr:[
                {
                    id:1,
                    name:'张三',
                    age:20
                },
                {
                    id:2,
                    name:'李四',
                    age:22
                },
                {
                    id:3,
                    name:'王五',
                    age:25
                }
            ]
        }
    });
</script>
</html>

(五)v-bind

① 作用: 可以绑定标签上的任何属性
② 格式:v-bind:属性="值"
③ 简写格式::属性="值"
④ 属性值一部分进行替换的格式::属性="'常量值' + vue对象data中的数据"
⑤ 案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-bind</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- 如果直接写属性名 , 不认识vue中定义的变量 -->
       <a href="addr">京东</a>

       <!-- 通过v-bind绑定的属性,能识别vue中定义的变量、方法-->
       <a v-bind:href="addr">百度</a>

       <a :href="addr2">中公</a>

       <a :href="'http://'+addr3">淘宝</a>
    </div>
</body>

<script>

    let app =  new Vue({
       el:"#app",
       data:{
            addr:"http://www.baidu.com",
            addr2:"http://www.offcn.com",
            addr3:"www.taobao.com"
       }
    });
</script>
</html>

练习-点击换样式

蓝色

color:blue;

border:1px solid blue;

box-shadow:0px 0px 3px black;

红色

color:red;

border:1px solid red;

box-shadow:0px 0px 3px black;

image

image-20210721201241401


(六)v-model

① 作用:表单元素的绑定
② 特点:双向数据绑定
	(1)vue对象中的数据发生变化可以更新到界面
	(2)通过界面可以更改vue对象中数据
	(3)v-model 会忽略所有表单元素的 value、 checked 、 selected 特性的初始值而总是将 Vue 实 例的数据作为数据来源。应该在data选项中声明初始值。
③ 案例:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-model</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="app">
        
            请输入您的个人信息:
            姓名:<input type="text" v-model="name"  /> 年龄: <input type="text"  v-model="age">  

            <hr>
            请核对您的个人信息 <br>
            姓名: {{name}}  <br>
            年龄: {{age}}
    </div>
      
</body>
<script>
    let app = new Vue({
        el:"#app",
        data:{
            name:'张三',
            age:20
        }
    })
</script>
</html>

(七)计算属性

计算属性可以时刻关注在vue中定义的关联的变量。  当这些关联的变量值发生变化,计算属性也会发生变化.

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>计算属性</title>
    <script src="js/vue.js"></script>
</head>
<body>
    
    <div id="app">
        <input type="text" v-model="num1" /> +  <input type="text" v-model="num2" /> 

        <p>
            <span>{{num1}}</span>   +    <span>{{num2}}</span>  = <span>{{sum}}</span>
           
        </p>

        <p>
            <span>{{num1}}</span>   *    <span>{{num2}}</span>  = <span>{{cheng}}</span>
        </p>
    </div>

</body>
<script>

    const app = new Vue({
        el:'#app',
        data:{
            num1:0,
            num2:0
        },
        computed:{
            sum(){
               return this.num1*1 + this.num2*1;  
            },
            cheng(){
                return this.num1 * this.num2;
            }
        }
    });
</script>
</html>

image-20210406114151765

案例说明:

1.修改数量、移除书籍后,总价会发生变化

2.当一本书籍都没有了,提示购物车为空,表格消失

image-20210723114412260

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>作业</title>

    <script src="vue.js"></script>
</head>
<body>
    
    <div id="app">
        <table v-show="items.length>0"  width="700" style="text-align: center;" border="1" cellspacing="0" cellpadding="0">
            <tr>
                <th></th>
                <th>书籍名称</th>
                <th>出版日期</th>
                <th>价格</th>
                <th>购买数量</th>
                <th>操作</th>
            </tr>

            <tr v-for="(item, index) in items">
                <td>{{item.id}}</td>
                <td>{{item.name}}</td>
                <td>{{item.date}}</td>
                <td>¥{{item.price}}</td>
                <td><button v-on:click="--item.count">-</button>{{item.count}}<button @click="++item.count">+</button></td>
                <td><button @click="items.splice(index,1)">移除</button></td>
            </tr>

        </table>
        
        <p v-show="items.length>0">总价:¥{{sum}}</p>

        <p v-show="items.length==0">购物车为空</p>
    </div>
</body>

<script>
    let app = new Vue({
        el:'#app',
        data:{
            items:[
                {id:1,name:'<<算法导论>>',date:'2006-9',price:85,count:1},
                {id:2,name:'<<UNIX编程艺术>>',date:'20016-2',price:59,count:1},
                {id:3,name:'<<编程珠玑>>',date:'2003-1',price:39,count:1},
                {id:4,name:'<<代码大全>>',date:'2012-7',price:128,count:1}
            ]
        },
        methods: {
            jian(book){
                if(book.count>1)
                    book.count--;
            },
            jia(book){
                book.count++;
            },
            remove(index){
                this.items.splice(index,1);
            }
        },
        computed:{
            sum(){
                let sum = 0;
                for(let i = 0 ; i < this.items.length;i++){
                   let book =  this.items[i];
                   sum+=book.price * book.count;
                }
                return sum;
            }
        }
    });
</script>

</html>

五、Vue的生命周期

	每个 Vue 实例在被创建时都要经过一系列的初始化过程 :创建实例,装载模板,渲染模板等等。Vue为生命周期中的每个状态都设置了钩子函数(监听函数)。每当Vue实例处于不同的生命周期时,对应的函数就会被触发调用。

image

image

钩子函数:
如:created代表在vue实例创建后;我们可以在Vue中定义一个created函数,代表这个时期的构造函数:

六、组件

(一)定义全局组件

我们通过Vue的component方法来定义一个全局组件。
Vue.component(组件名,{组件参数})
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 <script src="js/vue.js"></script>


</head>
<body>
 <div id="app">
    <con></con>
    <con></con>
 </div>
</body>
<script>

 let con = Vue.component("con",{
     template:`<div><p>次数{{count}}</p>
     <button type="button" @click="--count">-</button>
     <button type="button" @click="++count">+</button></div>`,
     data(){
        return {
             count:0
        }
     }

 });
 let app = new Vue({
     el:'#app'

 })
</script>
</html>

特点:
- 组件其实也是一个Vue实例,因此它在定义时也会接收:data、methods、生命周期函数等
- 不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有el属性。
- 但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
- 全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组件了。
- data的定义方式比较特殊,必须是一个函数。

注:
	定义组件要在Vue对象之前声明
	模板template中只能有一个root(根)

(二)定义局部组件

	一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。因此,对于一些并不频繁使用的组件,我们会采用局部注册。
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="js/vue.js"></script>


</head>

<body>
    <div id="app">
        
    </div>

    <div id="app1">
        <con></con>
        <con></con>
    </div>
</body>
<script>


let con =  {
                template: `<div><p>次数{{count}}</p>
        <button type="button" @click="--count">-</button>
        <button type="button" @click="++count">+</button></div>`,
                data() {
                    return {
                        count: 0
                    }
                }
            }

    let app = new Vue({
        el: '#app'

    })

    

    let app1 = new Vue({
        el: '#app1',
        components: {
            con: con
        }
    })
</script>

</html>
- components就是当前vue对象组件集合。
  - 其key就是子组件名称
  - 其值就是组件对象的属性
- 效果与刚才的全局注册是类似的,不同的是,这个conn组件只能在当前的Vue实例中使用

注:定义组件要在Vue对象之前声明

七、Vue的Ajax(axios)

在Vue.js中发送网络请求本质还是ajax,我们可以使用插件方便操作。

(一)安装

下载axios.js
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
用离线版的axios.js

(二)axios请求

GET请求



axios.get('/user?id=12345')
 .then(response => {
     console.log(response.data);
 });

axios.get('/user?id=12345').then(function(response){
    
})


POST请求

axios.post('/user', "name=迪丽热巴&age=23") .then(response => {
        console.log(response.data);
    });

(三)跨域问题

什么是跨域?
指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。
什么是同源策略?
是指协议,域名,端口都要相同,其中有一个不同都会产生跨域,在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
跨域问题怎么出现的?
开发一些前后端分离的项目,比如使用 Servlet + Vue 开发时,后台代码在一台服务器上启动,前台代码在另外一台电脑上启动,此时就会出现问题。
  比如:

    后台 地址为 http://192.168.70.77:8081
    前台 地址为 http://192.168.70.88:8080
  此时 ip 与 端口号不一致, 不符合同源策略,造成跨域问题。

image

处理思路

使用CORS,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
值得注意的是,目前主流浏览器都支持cors,会自动发出cors请求。在简单请求下,cors请求和同源请求的区别主要是浏览器的请求头信息中会多了一个origin字段。 这个字段表示本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这个请求。

因此在后续解决方案中,主要是服务器需要处理orgin这个请求头字段,同意跨域请求。

如何解决:
	后台解决(自定义过滤器)

    
package com.offcn.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/*")
public class CorsFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        // 不使用*,自动适配跨域域名,避免携带Cookie时失效
        String origin = request.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Origin", origin);

        // 自适应所有自定义头
        String headers = request.getHeader("Access-Control-Request-Headers");
        response.setHeader("Access-Control-Allow-Headers", headers);
        response.setHeader("Access-Control-Expose-Headers", headers);

        // 允许跨域的请求方法类型
        response.setHeader("Access-Control-Allow-Methods", "*");
        // 预检命令(OPTIONS)缓存时间,单位:秒
        response.setHeader("Access-Control-Max-Age", "3600");
        // 明确许可客户端发送Cookie,不允许删除字段即可
        response.setHeader("Access-Control-Allow-Credentials", "true");

        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}



原文地址:https://www.cnblogs.com/conglingkaishi/p/15315243.html