一. 了解MVC和MVVM模式

1.1 MVC模式

相信大家都很清楚MVC的设计模式,其实准确的来说MVC并不能算是一种设计模式,他算是一种框架模式。

经典的MVC模式中,M是指业务模型V是指用户界面C则是控制器,使用MVC的目的是将业务模型层用户界面层实现代码分离,使同一个程序可以使用不同的表现形式

下面详细的讲一下MVC三个分别代表什么

视图层

视图层也就是V,就是View,是指用户看到并与之交互的界面,也就是我们常常看见的网页,由Html元素则称的网页界面,或者软件的客户端界面。

业务模型层

业务模型层也就是M,即model模型是指模型表示业务规则。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。

控制器

控制器也就是C,即controller控制器是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

MVC指的使MVC模式的某种框架,它强制性的使应用程序的输入,处理和输出分开,使用MVC应用程序被分成三个核心的部件:模型、视图、控制器,他们各自处理自己的任务,最常见的MVC模式也就是JSP+servlet+JavaBean的模式。

其实说白了就是前端用户操控View层,View层去请求Controller层,然后Controller层把数据传输给Model层,改变Model层,然后Model再去改变View层

1.2 MVVM模式

相比于MVC模式不同的是,MVC模式采用的是面向对象的设计模式,而MVVM是基于组件,数据驱动的设计模式

MVVM模式指的是:Model-View-ViewModel

MVVM将**“数据模型数据双向绑定”**的思想作为核心,因此在View和Model之间没有联系,通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的,因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应到View上。即,ViewModel 是一个 View 信息的存储结构ViewModel 和 View 上的信息是一一映射关系

MVVM的设计原理是基于MVC来设计的,所以MVVM不能说算是一种创新,充其量是一种对于MVC的改造,这其中的ViewModel便是一个小小的创新
在这里插入图片描述

由上图可以得出ViewModel相当于是View和Model的连接桥,View可以通过事件绑定Model,Model可以通过数据绑定View,通过ViewModel可以实现数据和视图的完全分离

那么当创建了ViewModel 后,双向绑定是如何达成的呢?

  • 首先,我们将上图中的DOM Listeners 和 Data Bindings 看作两个工具,它们是实现双向绑定的关键。
  • 从 View 看,ViewModel 中的 DOM Listeners 工具会帮我们监测页面上DOM元素的变化,如果有 变化,则更改Model中的数据;
  • 从 Model 看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。

二. Vue模板语法

2.1 第一个Vue实例

使用Vue的时候我们需要注意几点

  • 导入相关的JS依赖
  • 需要绑定一个ID作为一个创建Vue实例的容器
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/vue-2.4.0.js"></script>

</head>
<body>
<!--使用vue时最外层一定要有一个包裹元素-->
<div id="app">
    <!--v-model表示数据双向绑定,V到M的双向绑定-->
    <!--v-model只能用在表单元素中-->
    <input type="text" id="username" name="username" v-model="msg" placeholder="请输入用户名">
    <!--vue取值语法,双大括号,会自动从data中获取对应的值,取不到也不会报错,找不到值为null-->
    <!--属性中使用data中的值必须使用v-bind指令,无需双大括号-->
    <p id="text" v-on:click="show" v-bind:title="info">{{msg}}</p>
</div>
</body>
<script>
    /*1. 创建VUE实例*/
    let vm = new Vue({
        el: "#app",     /*指定vue绑定容器*/
        data: {         /*设置vue可操作的数据内容*/
            msg: "今天学习vue很开心",
            info: "别看我,看他"
        },
        methods: {
            show: function () {
                alert("vue绑定的单击事件!");
                this.msg = "vue控制data中的值";
            }
        }
    });
</script>
</html>

这里面实现了在JS代码中和页面元素进行双向绑定的效果

2.2 生命周期函数

每个 Vue 实例在被创建之前都要经过一系列的初始化过程。例如需要设置数据监听、编译模板、挂载实例到 DOM、在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,给予用户机会在一些特定的场景下添加他们自己的代码。

也就是渲染页面过程中我们可以做的一些事情都可以编写在钩子函数中,相当于Javaweb中的过滤器的效果

2.2.1 生命周期函数图示

在这里插入图片描述

2.2.2 生命周期函数详解

以下排序是按照Vue生命周期的执行顺序进行排序

创建期间的函数

  • beforeCreate函数
    • 初始化Vue实例之前,此时只有el的值被挂载,data和methods中的值都不存在
    • 在这一阶段如果打印data的值和调用methods中的方法会报错
  • created函数
    • 实例化Vue后自动调用,此时data和methods中的内容已经存在
    • 此时调用data的值和methods中的方法则可以正常调用
  • beforeMount函数
    • 模板已经编译,但是还未渲染到页面上
  • mounted函数
    • 此时模板已经渲染到页面了(该函数执行表示vue实例已经真正初始化完成了)

运行期间的生命周期函数

  • beforeUpdate函数
    • 数据更新之前执行,此时data中的值已经更新,但是页面调用data的位置还未更新
  • update函数
    • 数据更新完成,此时data中的值和页面上显示的data的值相同

实例销毁期间

  • beforeDestroy函数
    • 此时实例还未被销毁,此时实例可正常使用
  • destroyed函数
    • 实例被销毁之后调用,此时所有绑定的事件和数据都会移除

代码演示

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/vue-2.4.0.js"></script>
</head>
<body>
    <div id="app">
        <h3>{{msg}}</h3>
        <button type="button" v-on:click="change">点我试试</button>
        <button type="button" @click="destroy">销毁实例</button>
    </div>
</body>
<script>
    /*对象的是姓名和表示属性值的变量名相同时可以简写*/
    let info = "aiaiaiaiaiai";
    new Vue({
        el: "#app",
        data: {
            msg: "你好,世界!",
            info
        },
        methods: {
            show() {
                console.log("我是vue实例methods中定义的函数");
            },
            change() {
                this.msg = "你被我发现了!";
            },
            destroy: function () {

            }
        },
        /*初始化Vue实例之前,此时只有el的值被挂载,data和methods中的值都不存在*/
        beforeCreate: function () {
            console.log("beforeCreate函数: data中的值是:" + this.msg); //报错
            this.show();
            console.log("beforeCreate执行完毕!");
        },
        /*实例化vue后自动调用,此时data和methods中的内容已经存在*/
        created() {
            console.log("created函数: data中的值是:" + this.msg);
            this.show();
            console.log("created执行完毕!");
        },
        /*模板已经编译,尚未渲染到页面*/
        beforeMount() {
            console.log("beforeMount");
        },
        /*模板已经渲染到页面了(该函数执行表示vue实例已经真正初始化完成)*/
        mounted() {
            console.log("mounted");
        },
        /*运行期间的生命周期函数*/
        /*数据更新之前执行,此时data中的值已经更新,但是页面调用data的位置还未更新*/
        beforeUpdate() {
            console.log("beforeUpdate函数: data中的值是:" + this.msg);
            console.log("页面中的值是:"+ document.querySelector("h3").innerText);
        },
        /*数据更新完成,此时data中的值和页面上显示的data的值相同*/
        updated() {
            console.log("updated函数: data中的值是:" + this.msg);
            console.log("页面中的值是:"+ document.querySelector("h3").innerText);
        },
        activated() {
            console.log("keep-alive组件激活时调用");
        },
        deactivated() {
            console.log("keep-alive组件被停用了");
        },
        beforeDestroy() {
            console.log("实例被销毁之前,此时实例正常可用");
        },
        destroyed() {
            console.log("实例被销毁之后调用,此时所有绑定的事件和数据都会移除");
        }

    });

    /*
    *
    * VUE生命周期: 表示vue从创建到运行再到结束的这期间,发生的各种事件和状态的统称为生命周期
    * 生命周期钩子和生命周期函数是相同的意思,只是叫法上的不同,他们都包含生命周期函数的事件和处理,都是自动触发
    *
    * 生命周期函数三大类
    * 1. 创建期间函数
    *   beforeCreate: 实例创建之前,此时data中和methods中绑定的数据和方法都不可用
    *   created: 实例创建之后,此时data中和methods中绑定的数据和方法正常使用
    *   beforeMount: 组件以及加载但是未渲染到页面
    *   mounted: 组件加载并且完成渲染
    *
    * 2. 运行期间函数
    *   beforeUpdate: 状态更新之前,此时data中的值已经更新,但是页面未重新渲染
    *   updated: 状态更新之后,此时data中的值已经更新,页面渲染完毕
    *
    * 3. 销毁期间
    *   beforeDestroy: 实例销毁之前,此时实例仍然可用(执行销毁和彻底销毁之间的这个状态)
    *   destroyed: 实例彻底销毁之后触发 
    * */
</script>
</html>

2.3 插值表达式

插值表达式相当于原生JS中的innerText和innerHTML两种方法

一个可以向页面渲染HTML标签,一个是用来渲染文本内容的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/vue-2.4.0.js"></script>

</head>
<body>
    <div id="app">
        <!--插值表达式-->
        <p>{{msg}}</p>
        {{msgHtml}}
        <hr>
        <!--v-html指令用来向页面渲染HTML标签,等价于innerHTML-->
        <p v-html="msg">我是脑瘫</p>
        <p v-html="msgHtml"></p>

        <!--v-text指令用来向页面渲染文本内容,等价于innerText-->
        <p v-text="msg"></p>
        <p v-text="msgHtml"></p>

        <!--插值表达式{{}}和v-text指令的区别,v-text会覆盖他所在的整个标签,插值表达式不会-->

        <!--解决插值表达式的闪烁问题使用v-cloak指令-->
        <p v-cloak>{{msg}}</p>

    </div>
</body>
<script>
    new Vue({
        el: "#app",
        data: {
            msg: "不过520",
            msgHtml: `<h3>不过那是不行的</h3>`,
        }
    });
</script>
</html>

2.4 属性和样式处理

属性和样式的处理也就是使用vue的语法,指令来处理属性中的值

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/vue-2.4.0.js"></script>
    <style>
        .test1 {
            background: blue;
        }
        .test2 {
            color: white;
        }
    </style>
</head>
<body>
    <div id="app">
        <!--v-bind:指令用来处理属性中使用data的值,简写为:-->
        <p v-bind:id="id" :title="title">你好,小明</p>
        <!--v-bind指令中支持js代码-->
        <p :title="title + '大明'">你好,大明</p>
        <p :title="title.substr(0,2)">你好傻逼</p>
        <hr>

        <p style="color: red;">你好,小红</p>
        <!--一定要注意的点: v-bind中要么调用data里的属性名,要么自己写正确的js代码-->
        <p :style="{color: 'red'}">你好小红</p>
        <p :style="style">你好小粉</p>
        <p :style="style" :title="'vue中控制属性'">你好小粉</p>


        <input type="checkbox" :checked="true">

        <p :style="[style,style2]">黄思源大傻逼</p>

        <p id="pc" class="test1 test2">你好,小张</p>
<!--        <p :class="['test1' 'test2']">你好,小张</p>-->
        <p :class="['test1',{'test2':flag}]">你好,小张</p>
        <p :class="['test1',{'test2':flag}]">你好,小张</p>
        <p :class="classObj">你好大张</p>
        <button v-on:click="toggle" type="button">切换样式</button>
    </div>
</body>
<script>
    new Vue({
       el: "#app",
       data: {
           id: "username",
           title: "你好",
           style: {
               color: 'pink',
               fontSize: '30px'
           },
           style2: {
               fontWeight: '700'
           },
           flag: false,
           classObj: {test1: true,test2: true}
       },
       methods: {
           toggle() {
               this.flag = !this.flag; /*只有布尔类型可以使用这种写法*/
           }
       },
       created() {
           let pc = document.querySelector("#pc");
           console.log(pc.className);
           /*className属性直接赋值时覆盖操作,不管你原先有多少样式,都会被覆盖为给的值*/
           pc.classList.add('test3');
           // pc.classList.remove('test2');
       }

    });
</script>
</html>

2.5 事件绑定

Vue的事件绑定方法名和jQuery数据绑定的方法名一样,只是调用方式不一样

v-on:+事件方法名为调用方法

@+事件方法名为简写调用方法

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/vue-2.4.0.js"></script>

</head>
<body>
    <div id="app">
        <button type="button" v-on:click="getCount1">{{count}}</button>
        <button type="button" @click="getCount2">{{count}}</button>
    </div>
</body>
<script>
    new Vue({
        el: "#app",
        data: {
            count: 0,
        },
        methods: {
            getCount1() {
                this.count += 1;
            },
            getCount2() {
                this.count -= 1;
            }
        }
    });
</script>
</html>

2.6 事件修饰符

首先了解以下事件机制

DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

事件捕获:通俗的理解就是,当鼠标点击或者触发dom事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。

**事件冒泡:**与事件捕获恰恰相反,事件冒泡顺序是由内到外进行事件传播,直到根节点。

无论是事件捕获还是事件冒泡,它们都有一个共同的行为,就是事件传播,它就像一跟引线,只有通过引线才能将绑在引线上的鞭炮(事件监听器)引爆,试想一下,如果引线不导火了,那鞭炮就只有一响了!!!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/vue-2.4.0.js"></script>

</head>
<body>
<div id="app">
    <!--.stop修饰符表示事件的冒泡到此为止(阻止事件冒泡)-->
    <div style="height: 200px;width: 200px;background-color: pink" @click="divClick">
        <p style="height: 100px;width: 100px;background-color: yellow;" @click.stop="pClick">
            <button type="button" @click="btnClick">阻止冒泡</button>
        </p>
    </div>
    <!--.capture修饰符表示事件捕获-->
    <div style="height: 200px;width: 200px;background-color: pink" @click.capture="divClick">
        <p style="height: 100px;width: 100px;background-color: yellow;" @click.capture="pClick">
            <button type="button" @click.capture="btnClick">阻止冒泡</button>
        </p>
    </div>
    <!--.prevent修饰符阻止默认行为-->
    <a href="https://www.baidu.com" target="_blank" @click.prevent="aClick">有问题,先百度</a>
    <!--.self修饰符表示该函数只在自身触发-->
    <div style="height: 200px;width: 200px;background-color: pink" @click="divClick">
        <p style="height: 100px;width: 100px;background-color: yellow;" @click.self="pClick">
            <button type="button" @click="btnClick">阻止冒泡</button>
        </p>
    </div>
    <!--.once修饰符表示该事件只生效一次-->
    <!--事件修饰符可以组合使用-->
    <a href="https://www.baidu.com" target="_blank" @click.prevent.once="aClick">有问题,先百度</a>
</div>
</body>
<script>
    new Vue({
        el:"#app",
        data:{

        },
        methods:{
            aClick(){
                console.log("您点击了a标签");
            },
            divClick(){
                console.log("您点击的是div");
            },
            btnClick(){
                console.log("您点击的是btn");
            },
            pClick(){
                console.log("您点击的是p");
            }
        }
    });
    /*
    * 使用vue来实现tabs切换效果
    * */
</script>
</html>

2.7 使用vue实现tabs切换

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/vue-2.4.0.js"></script>
    <style>
        #app div {
            height: 200px;
            width: 200px;
            display: none;
        }
        #app div.active{
            display: block;
        }
        .btn-active {
            background: teal;
            color: white;
        }
    </style>

</head>
<body>
    <div id="app">
        <button :class="{'btn-active':index===1}" type="button" @click="tabs(1)">按钮1</button>
        <button :class="{'btn-active':index===2}" type="button" @click="tabs(2)">按钮2</button>
        <button :class="{'btn-active':index===3}" type="button" @click="tabs(3)">按钮3</button>
        <div :class="{'active':index===1}">内容1</div>
        <div :class="{'active':index===2}">内容2</div>
        <div :class="{'active':index===3}">内容3</div>
    </div>
</body>
<script>
    new Vue({
        el: "#app",
        data: {
            index: 1
        },
        methods: {
            tabs(i){
                this.index = i;
            }
        }
    });
</script>
</html>

三. Vue流程语句

Vue里面也有if语句和for循环语句,下面就来介绍一下Vue中的逻辑判断语句和循环语句

3.1 v-if指令

Vue的逻辑判断语句其实和JS里面的逻辑判断语句差不多的,只不过Vue中使用的是指令控制,并且Vue的逻辑判断语句是写在标签上面的指令,判断指令内的值是否为true或false用于是否显示标签内容

下面是代码案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../js/vue-2.4.0.js"></script>

</head>
<body>
  <div id="app">
    <!--v-if通过给定的表达式或布尔值来决定这个标签是否加载-->
    <p v-if="msgShow">{{msg}}</p>
    <!--v-else-if和v-else-->
    <p v-if="age<=12">儿童</p>
    <!--使用if判断的时候之间不能有其他额外的标签-->
    <p v-else-if="age<=18">未成年</p>
    <p v-else>成年人</p>

    <!--切换登录方式-->
    <!--v-if切换标签的时候,为了高效渲染页面,采用的部分替换方案而不是完整替换-->
    <!--设置不同的key值来确保每次都会完全重新渲染,结合实际需求来决定要不要设置key-->
    <div class="login">
      <div v-if="isPhone" key="phone">
        <label for="phone">手机号</label>
        <input type="text" id="phone" name="phone" placeholder="请输入手机号">
      </div>
      <!--条件渲染指令必须写在标签上,需要控制多个标签的时候,一般会给多个标签添加一个公用的父级标签-->
      <div v-else key="username">
        <div >
          <label for="username">用户名</label>
          <input type="text" id="username" name="username" placeholder="请输入用户名">
        </div>
        <div>
          <label for="password">密码</label>
          <input type="text" id="password" name="password" placeholder="请输入密码">
        </div>
        <div>
          <label for="respwd">确认密码</label>
          <input type="text" id="respwd" name="respwd" placeholder="请输入确认密码">
        </div>
      </div>

      <button type="button" @click="change">切换登录方式按钮</button>
    </div>
  </div>


  <!--v-show和v-if使用是一致的,但是v-show只有这一个标签单独来用,并且v-show是操作标签的display属性控制标签的显示和隐藏-->
</body>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      msg: "你好,世界!",
      msgShow: true,
      age: 22,
      isPhone: true
    },
    methods: {
      change() {
        this.isPhone = !this.isPhone;
      }
    }
  });
</script>
</html>

3.2 v-for指令

Vue中的for循环语句其实也挺好理解,Vue中的所有指令都是写在标签里面的,所以vue的for循环语句也是在标签中编写,下面是带来的代码案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/vue-2.4.0.js"></script>

</head>
<body>
    <div id="app">
        <!--v-for遍历数组-->
        <div>
            <b v-for="a in arr">{{a}}</b>
        </div>
        <!--v-for遍历数组带下标-->
        <div>
            <p v-for="(a,i) in arr">下标{{i}}的值是{{a}}</p>
        </div>
        <hr>
        <!--v-for遍历对象-->
        <div>
            <p v-for="o in obj">{{o}}</p>
        </div>
        <!--v-for遍历对象并获取key-->
        <div>
            <p v-for="(value,key) in obj">
                key的值: {{k}},value的值: {{v}}
            </p>
        </div>
        <!--v-for遍历对象获取key和index(尽量不要使用index参数,因为对象的key是无序的)-->
        <div>
            <p v-for="(value,key,index) in obj">
                下标: {{index}},key: {{key}},value: {{value}}
            </p>
        </div>
        <hr>
        <!--v-for遍历字符串-->
        <div>
            <i v-for="s in str">{{s}}</i>
        </div>
        <hr>
        <!--v-for遍历整数-->
        <div>
            <b v-for="n in num">{{n}}</b>
        </div>
        <hr>
        <div>
            <p v-for="stu in stuList">
                {{stu.name}}的年龄是{{stu.age}}
            </p>
        </div>
        <hr>
        <div>
            <p v-for="(stu,index) in stuList" :key="index">姓名: {{stu.name}},年龄: {{stu.age}}</p>
        </div>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            arr: ['a','b','c'],
            obj: {
                name: "张三",
                age: 18
            },
            str: "hello world",
            num: 10,
            stuList: [{name: "张三丰",age: 120},{name: "张无忌",age: 30},{name: "陈奕迅",age: 28}]
        },
        methods: {}
    });
</script>
</html>

3.3 template模板

有些标签或有些特定条件下不能给多个标签设置统一父类标签时,使用vue提供的专用模板标签来实现,大概意思也就是说在vue中如果使用指令的话必须使用标签包裹,不然不会显示,那么这个时候如果没有办法提供父类标签的时候,就可以使用template模板来替代父类标签

下面是template的使用方法

<body>
    <!--template标签是一个纯粹的包裹容器,他不会在页面中被显示-->
    <template v-if="age>=18">
      <p>今年{{age}}岁</p>
      <p>是成年人了</p>
    </template>
    <template v-else>
      <p>今年{{age}}岁</p>
      <p>是未成年人</p>
    </template>
    <!--被控制的标签本身如果有统一的父级标签,可以直接使用,如果没有统一的父级标签,不推荐自己加div包裹,而应该使用template标签来包裹-->
</body>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      msg: "你好,世界!",
      msgShow: true,
      age: 22,
      isPhone: true
    },
    methods: {
      change() {
        this.isPhone = !this.isPhone;
      }
    }
  });
</script>

3.4 数据表格增删改查案例

这里提供了一个小案例,是使用Vue对于数据表格进行增删改查的一个小Demo,没有通过数据库交互,做的一个比较简单的一个小案例,以下是代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>数据表格实现</title>
    <script src="../js/vue-2.4.0.js"></script>

</head>
<body>
    <div id="app">
        <div v-if="isEdit">
            <form>
                <div>
                    <label for="id">编号</label>
                    <input type="text" v-model="id" readonly name="id" id="id" placeholder="请输入编号">
                </div>
                <div>
                    <label for="bookName">图书名</label>
                    <input type="text" v-model="book.bookName" name="bookName" id="bookName" placeholder="请输入图书名">
                </div>
                <div>
                    <label for="price">价格</label>
                    <input type="text" v-model="book.price" name="price" id="price" placeholder="请输入价格">
                </div>
                <div>
                    <label for="profile">简介</label>
                    <textarea cols="30" v-model="book.profile" rows="10" name="profile" id="profile" placeholder="请输入简介"></textarea>
                </div>
                <div>
                    <button type="button" @click="save">保存</button>
                </div>
            </form>
        </div>
        <div>
            <button type="button" @click="showEdit()">添加数据</button>
            <div v-if="bookList.length===0">
                暂无数据
            </div>
            <div v-else>
                <form>
                    <input type="text" placeholder="请输入书名" v-model="bname">
                    <input type="text" placeholder="请输入价格" v-model="search.bprice">
                    <button type="button" @click="searchList">搜索</button>
                </form>
            </div>
            <div>
                <table width="60%" border="1px">
                    <tr>
                        <th>编号</th>
                        <th>书名</th>
                        <th>价格</th>
                        <th>简介</th>
                        <th>操作</th>
                    </tr>
                    <tr v-for="(b,i) in searchList(bname)" :key="i">
                        <td>{{b.id}}</td>
                        <td>{{b.bookName}}</td>
                        <td>{{b.price}}</td>
                        <td>{{b.profile}}</td>
                        <td>
                            <button type="button" @click="showEdit(b.id)">修改</button>
                            <button type="button" @click="del(b.id)">删除</button>
                        </td>
                    </tr>
                </table>
            </div>
        </div>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            isEdit: false,
            search: {},
            book: {
                /*bookName: '',
                price: '',
                profile: ''*/
                /*操作对象的时候可以只给一个空对象*/
            },
            bookList: [{
                id: 1,
                bookName: "三体1",
                price: 30,
                profile: "三体第一部"
            },{
                id: 2,
                bookName: "三体2",
                price: 40,
                profile: "三体第二部"
            },{
                id: 3,
                bookName: "三国演义",
                price: 50,
                profile: "三国演义真性情"
            },{
                id: 4,
                bookName: "盗墓笔记",
                price: 80,
                profile: "挖坑填补上,烂尾小说第一名"
            }],
            type: "add",
            bname: ""
        },
        created() {
            this.id = this.bookList.length+1;
        },
        methods: {
            showEdit(id) {
                this.isEdit = true;
                if (id) {
                    /*修改时根据id去所有图书信息中匹配,找到则停止*/
                    for (let i = 0; i < this.bookList.length; i++) {
                        if (this.bookList[i].id == id) {
                            this.book = this.bookList[i];
                            break;
                        }
                    }
                    this.type = "";
                }else {
                    this.type = "add";
                    this.book.id = this.id;
                    this.id++;
                }
                this.book.id = this.id;
            },
            save() {
                if (!this.book.bookName) {
                    alert("图书名不能为空!");
                    return;
                }
                if (!this.book.price) {
                    alert("价格不能为空!");
                    return;
                }
                if (!this.book.profile) {
                    alert("简介不能为空!");
                    return;
                }
                if (this.type === "add") {
                    let oldLen = this.bookList.length;
                    this.bookList.push(this.book);
                    if (this.bookList.length === oldLen + 1) {
                        alert("数据添加成功!");
                        this.isEdit = false;
                    }else {
                        alert("数据添加失败!");
                    }
                }else {
                    /*修改数据中的内容*/
                    for (let i = 0; i < this.bookList.length; i++) {
                        if (this.bookList[i].id === this.book.id) {
                            this.bookList[i] = this.book;
                            break;
                        }
                    }
                }
                this.book = {};
                this.isEdit = false;
            },
            del(id) {
                if (confirm('确定删除本条数据么?')) {
                    for (let i = 0; i < this.bookList.length; i++) {
                        if (this.bookList[i].id == id) {
                            this.bookList.splice(i,1);
                            break;
                        }
                    }
                }
            },
            searchFn() {
                console.log(this);  //指向vue对象自己
                /*根据完整书名查询*/
                /*这里直接更新bookList会导致bookList的原始数据发生变化,导致数据无法返回*/
                /*this.bookList = this.bookList.filter(item=>{
                    if (item.bookName === this.search.bname) {
                        return item.bookName === this.search.bname;
                    }
                });*/
                this.bookList = this.bookList.filter(item=>item.bookName.includes(this.search.bname));
            },
            searchList(bname) {
                console.log(bname);
                if (bname) {
                    console.log("进入了方法");
                    return this.bookList.filter(item=>item.bookName.includes(this.bname));
                }
                return this.bookList;
            }
        }
    });
</script>
</html>

四. 前后端分离概念

这里想补充一个点,之前一直搞不懂前后端分离的架构模式,这两天由于有这方面的需求,想写一个前后端分离的项目,和老师聊天的时候慢慢了解到了这个概念,之前我写的代码不论是Java代码还是Node代码,前端页面跳转的时候总会经过一个controller控制器,因为前端页面跳转的过程中避免不了会携带一些与数据库交互的参数,还有Node架构和springboot架构中View包下的文件和template包下的文件都是没有办法直接通过链接访问的,这也是数据安全性的一种吧,这个时候Vue就衍生了路由机制,通过路由进行页面跳转,(路由这个点在后面的博客中会详细提到)路由的机制是可以携带参数跳转的,这一点很重要。
前后端分离也是这个样子,在通过路由机制进行页面跳转的时候,携带的信息跳到了另一个页面,body中的数据还未被渲染上,这个时候Vue的核心,双向绑定机制就发挥了作用,通过参数想model层进行交互,获取数据,然后再通过Vue的双向绑定,将Ajax或者Axios获取到的参数进行处理,直接在页面上渲染出来用户需要看到的数据。

以上就是本次博客的全部内容了,里面涉及了一些Vue的基础入门,其实不管是前端开发人员还是后端开发人员,对于Vue的使用还是需要一定得了解的,Vue的入门还是比较简单的,不过庆幸的是自己在之前有了解过原生JS的使用,而且对于原生JS了解的也比较多,所以Vue学起来可能不会太过吃力,所以说基础还是比较重要的,大家在学习过程中一定要把基础打牢,以上博客的内容代表着自己的观点,本人是一名后端转前端的初学者,大家看后有什么错误或者有什么需要改正的地方欢迎大家提出,大家一起学习,共同进步!

最近很少更新博客了,一直忙着其他事情,博客也没有写太多,接下来会恢复博客的日常更新,毕竟还是要努力学习的,充实自己,忙起来就好了,加油!!!

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐