目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

VUE

vscode插件

快速上手

引包
 (如需下载自己要的版本在vue后面加上@版本号)

# 下载vue,选取 vue.js 文件
npm install vue	//cnpm install vue

# 页面引入刚下载的包
<script type="text/javascript" src="vue.js"></script>

留坑
 即留一个vue模板插入的地方或者是vue代码对其生效的地方

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

实例化
 创建Vue实例

示例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 1.导包 -->
    <script src="./js/vue.min.js"></script>
</head>

<body>
    <!-- 创建ip为app的div -->
    <div id="app">
        <!--差值表达式 可以获取vue实例中的数据-->
        {{name}} <br> {{school.name}} {{school.mobile}}
        <ul>
            <li>{{names[0]}}</li>
            <li>{{names[1]}}</li>
            <li>{{names[2]}}</li>
        </ul>
    </div>
</body>

<script>
    //3.创建Vue实例
    var VM = new Vue({
        el: "#app", //el挂载点
        data: { //data Vue中用到的数据
            name: "Hello Vue!",
            //定义对象类型
            school: {
                name: "soulboy",
                mobile: "1001001",
            },
            //数组类型
            names: ["尼古拉斯", "高中雅", "高中美"]
        },
    });
</script>

</html>

常用指令

什么是指令
 在vue中提供一些对于页面+数据的更为方便的操作,这些操作就叫做指令。譬如在HTML页面中这样使用 <div v-xxx=''></div>
 在vue中v-xxx就是vue的指令,指令就是以数据去驱动DOM行为的,简化DOM操作。

示例

<!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>
    <!-- 1.导包 -->
    <script src="./js/vue.min.js"></script>
</head>

<body>
    <!-- 创建ip为app的div -->
    <div id="app">

        <!-- v-text:获取普通文本,覆盖原有标签的innerHTML内容-->
        <!--插值表达式:不会覆盖原来的内容-->
        <h2>{{message}}喜欢IT</h2>
        <h2 v-text="message">喜欢IT</h2>
        <h2 v-text="message+1">喜欢IT</h2>
        <h2 v-text=" message+' abc'">喜欢IT</h2>

        <!-- v-html:获取普通文本并解析HTML(设置元素的innerHTML)-->
        <h2 v-html="url"></h2>

        <!-- v-on:绑定事件 -->
        <input type="button" value="点击按钮" v-on:click="show" />
        <input type="button" value="点击按钮" @click="show" />
        <input type="button" value="点击按钮" @dblclick="show" />
        <h2 @click="changeFood">{{food}}</h2>
        <!-- 案例:计数器-->
        <input type="button" value="+" @click="increase">
        <span>{{num}}</span>
        <input type="button" value="-" @click="decrease">
        <br>
        <!-- 函数传参:事件绑定方法后可以传递参数,定义方法时需要定义形参来接收参数 -->
        <input type="button" value="礼物刷起来" @click="showTime(666,' 太屌了!!! ')">
        <!-- 事件修饰符: 指定哪些方式可以触发事件(回车键之后触发事件,细化事件)-->
        <input type="text" @keyup.enter="hi" />

        <!-- v-show:依据布尔值切换元素显示状态(操作的是样式 style="display: none;") 
             v-if:依据布尔值切换元素显示状态(操作的是DOM元素节点) 
             true 显示
             false 隐藏 
             频繁切换使用 v-show
             不频繁使用 v-if
        -->
        <input type="button" value="切换状态" @click="changeShow"><br>
        <img v-show="isShow" src="./img/boss.jpeg" width="200" height="200" /><br>
        <img v-show="age > 18" src="./img/boss.jpeg" width="200" height="200" /><br>

        <!-- v-bind:设置元素的属性(src class...) 
             语法: v-bind:属性名=表达式
             简写:  :属性名
        -->
        <img src="./img/saga.jpeg" width="200" height="200" /><br>
        <img v-bind:src="imSrc" :width="width" :height="height" /><br>

        <!-- v-for:根据数据生成列表 
             1.数组经常和v-for结合使用
             2.语法格式:(item,index) in 数据
             3.数组的长度变化,会同步更新到页面,响应式的
        -->
        <ul>
            <!--在li标签中 获取数组的元素 -->
            <li v-for="(item,index) in arr">
                {{index+1}}城市:{{item}}
            </li>
        </ul>
        <!-- 遍历对象数组 -->
        <input type="button" value="添加数据" @click="add">
        <input type="button" value="移除数据" @click="remove">
        <h2 v-for="p in persons">
            姓名:{{p.name}} 年龄:{{p.age}}
        </h2>

</body>
<script>
    //3.创建Vue实例
    var VM = new Vue({
        //el挂载点
        el: "#app",
        //data Vue中用到的数据
        data: {
            message: "soulboy",
            url: "<a href='https://www.baidu.com'>百度一下</a>",
            food: "麻辣小龙虾",
            num: 0,
            isShow: true,
            age: 19,
            imSrc: "./img/saga.jpeg",
            width: 200,
            height: 200,
            arr: ["上海", "开封", "郑州", "深圳", "广东"],
            //对象数组
            persons: [{
                name: "高中美",
                age: "18"
            }, {
                name: "高中直",
                age: "17"
            }],
        },
        //Vue存放方法的位置
        methods: {
            show: function() {
                alert("在学习!!!");
            },
            changeFood: function() {
                //使用this获取data中的数据
                this.food += "真好吃";
            },
            increase: function() {
                if (this.num < 10) {
                    this.num++;
                } else {
                    alert("不能大于10!")
                }
            },
            decrease: function() {
                if (this.num > 0) {
                    this.num--;
                } else {
                    alert("不能小于0!")
                }
            },
            showTime: function(p1, p2) {
                console.log(p1);
                console.log(p2);
            },
            hi: function() {
                alert("你好吗?");
            },
            changeShow: function() {
                this.isShow = !this.isShow;
            },
            add: function() {
                //向数组添加元素 push
                this.persons.push({
                    name: "妞妞",
                    age: "18"
                });
            },
            remove: function() {
                //向数组添加元素 push
                this.persons.shift();
            },
        },
    });
</script>

</html>

MVVM

 MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式
 MVVM模式将页面,分层了 M 、V、和VM ,解释为:

  • Model: 负责数据存储
  • View: 负责页面展示
  • View Model: 负责业务逻辑处理(比如Ajax请求等),对数据进行加工后交给视图展示
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 1.导包 -->
    <script src="./js/vue.min.js"></script>
</head>

<body>
    <!-- 创建ip为app的div -->
    <div id="app">
        <!-- View 视图部分 -->
        {{name}}
    </div>
</body>

<script>
    //3.创建Vue实例(VM ViewModel)
    var VM = new Vue({
        el: "#app", //el挂载点
        data: { //data Vue中用到的数据(Model)
            name: "Hello Vue!",
            //定义对象类型
            school: {
                name: "soulboy",
                mobile: "1001001",
            },
            //数组类型
            names: ["尼古拉斯", "高中雅", "高中美"]
        },
    });
</script>

</html>

首先,我们将上图中的DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键。

  • 从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;
  • 从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素

MVVM的思想,主要是为了让我们的开发更加的方便,因为MVVM提供了数据的双向绑定

v-model

作用: 获取和设置表单元素的值(实现双向数据绑定)

双向数据绑定

  • 单向绑定: 就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新。
  • 双向绑定: 用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定。

什么情况下用户可以更新View呢?
 填写表单就是一个最直接的例子。当用户填写表单时,View的状态就被更新了,如果此时MVVM框架可以自动更新Model的状态,那就相当于我们把Model和View做了双向绑定:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 1.导包 -->
    <script src="./js/vue.min.js"></script>
</head>

<body>
    <div id="app">
        <!-- 通过button注册实践改变model -->
        <input type="button" value="修改message" @click="update" />

        <!-- View(视图) -->
        <!-- 单向数据绑定(v-bind):将model绑定到view上,当model发生变化时,view会随之变化 -->
        <!-- <input type="text" v-bind:value="message" /> -->
        <!-- 双向数据绑定(v-model):view视图发生变化时,model也会随之改变 -->
        <input type="text" v-model="message" />
        <input type="text" v-model="password" />
        <h2>{{message}}</h2>
        <h2>{{password}}</h2>
    </div>
</body>
<script>
    //VM(业务逻辑控制)
    var VM = new Vue({
        el: "#app",
        //Model(数据模型) 
        data: {
            message: "soulboy",
            password: 123,
        },
        methods: {
            update: function() {
                this.message = "拉钩";
            },
        },
    });
</script>

</html>

记事本案例

D:\Project\vscode\vue_text\记事本案例\记事本案例.html

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <title>小黑记事本</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <meta name="robots" content="noindex, nofollow" />
    <meta name="googlebot" content="noindex, nofollow" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" type="text/css" href="../css/index.css" />
  </head>

  <body>
    <!-- VUE示例接管区域 -->
    <section id="app">
      <!-- 输入框 -->
      <header class="header">
        <h1>VUE记事本</h1>
        <input
          autofocus="autofocus"
          autocomplete="off"
          placeholder="输入日程"
          class="new-todo"
          v-model="inputValue"
          @keyup.enter="add"
        />
      </header>

      <!-- 列表区域 -->
      <section class="main">
        <ul class="listview">
          <!-- 1.使用v-for指令 生成列表结构 -->
          <li class="todo" v-for="(item,index) in list">
            <div class="view">
              <span class="index">{{index+1}}</span> <label>{{item}}</label>
              <!-- 2.删除操作 传递index -->
              <button class="destroy" @click="remove(index)"></button>
            </div>
          </li>
        </ul>
      </section>
      <!-- 统计和清空 -->
      <footer class="footer">
        <span class="todo-count">
          <strong>{{list.length}}</strong> items left
        </span>
        <button class="clear-completed" @click="clear()">
          Clear
        </button>
      </footer>
    </section>
  </body>
  <!-- 开发环境版本,包含了有帮助的命令行警告 -->
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var VM = new Vue({
      el: "#app",
      data: {
        list: ["写代码", "吃饭", "睡觉", "打豆豆"],
        inputValue: "996还是997",
      },
      methods: {
        //新增日程方法
        add: function () {
          //将用户输入的内容添加到list
          this.list.push(this.inputValue);
        },
        remove: function (index) {
          console.log(index);
          //使用 splice(元素的索引,删除几个)
          this.list.splice(index, 1);
        },
        //清空操作
        clear: function () {
          this.list = [];
        },
      },
    });
  </script>
</html>

Ajax

 Ajax 是指一种创建交互式网页应用的开发技术。Ajax = 异步 JavaScript 和 XML。

  • Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新(局部更新)。传统的网页如果需要更新内容,必须重载整个网页页面。

  • 简单记: Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术, 维护用户体验性, 进行网页的局部刷新.

    异步与同步

     浏览器访问服务器的方式

  • 同步访问: 客户端必须等待服务器端的响应,在等待过程中不能进行其他操作

  • 异步访问: 客户端不需要等待服务的响应,在等待期间,浏览器可以进行其他操作

axios

 VUE中结合网络数据进行应用的开发

  • 目前十分流行网络请求库,专门用来发送请求,其内部还是ajax,进行封装之后使用更加方便
  • axios作用: 在浏览器中可以帮助我们完成 ajax异步请求的发送.

导包

<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

请求方式,以GET和POST举例
GET

axios.get(地址?key=value&key2=value2).then(function(response){},function(error){});


POST
axios.post(地址,{key:value,key2:value2}).then(function(response){},function(error){})

根据接口文档, 访问测试接口,进行测试

接口1:随机笑话

请求地址:https://autumnfish.cn/api/joke/list
请求方法:get
请求参数:num(笑话条数,数字)
响应内容:随机笑话

接口2:用户注册

请求地址:https://autumnfish.cn/api/user/reg
请求方法:post
请求参数:username(用户名,字符串)
响应内容:注册成功或失败

示例代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      /*
        axios总结
          1.axios必须要导包
          2.使用get或者post方式发送请求
          3.then方法 中的回调函数,会在请求成功或者失败的时候被触发
          4.通过回调函数的形参,可以获取响应的内容
      */

    </style>
  </head>
  <body>
    <input type="button" value="get请求" id="get" />
    <input type="button" value="post请求" id="post" />
  </body>
  <script src="./js/axios.min.js"></script>
  <script>
    /*
    随机笑话接口测试
      请求地址:https://autumnfish.cn/api/joke/list
      请求方法:get
      请求参数:num(笑话条数,数字)
      响应内容:随机笑话
  */
    document.getElementById("get").onclick = function () {
      axios.get("https://autumnfish.cn/api/joke/list?num=1").then(
        function (resp) {
          //调用成功
          console.log(resp);
        },
        function (err) {
          //调用失败
          console.log(err);
        }
      );
    };

    /*
    用户注册
      请求地址:https://autumnfish.cn/api/user/reg
      请求方法:post
      请求参数:username:"用户民"
      响应内容:注册成功或失败
    */
    document.getElementById("post").onclick = function () {
      axios
        .post("https://autumnfish.cn/api/user/reg", { username: "张abc" })
        .then(
          function (resp) {
            console.log(resp);
          },
          function (error) {
            console.log(error);
          }
        );
    };
  </script>
</html>

笑话案例(VUE+AXIOS)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>vue+axios获取笑话</title>
    <style>
      /*
        1.axios回调函数中,this的指向已经改变,无法访问data中的数据
        2.解决方案: 将this进行保存
      */
    </style>
  </head>
  <body>
    <div id="app">
      <input type="button" value="点击获取一个笑话" @click="getJoke" />
      <p>{{joke}}</p>
    </div>
  </body>

  <script src="../js/vue.min.js"></script>
  <script src="../js/axios.min.js"></script>
  <script>
    /*
        请求地址:https://autumnfish.cn/api/joke
        请求方法:get
        请求参数:无
        响应内容:随机笑话
    */
    var VM = new Vue({
      el: "#app",
      data: {
        joke: "笑口常开",
      },
      methods: {
        getJoke: function () {
          //把this进行保存
          var that = this;

          //异步访问
          axios.get("https://autumnfish.cn/api/joke").then(
            function (resp) {
              console.log(resp.data);
              //在回调函数内部 ,this无法正常使用,需要提前保存起来
              console.log(that.joke); //undefined
              that.joke = resp.data;
            },
            function (error) {}
          );
        },
      },
    });
  </script>
</html>

查询天气案例(VUE+AXIOS)

D:\Project\vscode\vue_text\查询天气案例\查询天气案例.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>天气查询</title>
    <link rel="stylesheet" href="css/reset.css" />
    <link rel="stylesheet" href="css/index.css" />

    <style>
      /*
        1.应用的逻辑代码 建议与页面进行分离,使用单独的JS编写
        2.axios中 回调函数中的this 需要先保存 再使用
        3.服务器返回的数据比较复杂,获取数据的时候 要注意层级结构
      */
      [v-cloak]{
        display: none;
      }
    </style>
  </head>

  <body>
    <div class="wrap" id="app" v-cloak>
      <div class="search_form">
        <div class="logo">天气查询</div>
        <div class="form_group">
          <input
            type="text"
            class="input_txt"
            placeholder="请输入要查询的城市"
            v-model="city"
            @keyup.enter="searchWeather"
          />
          <button class="input_sub">回车查询</button>
        </div>
      </div>
      <ul class="weather_list">
        <!-- 展示数据 -->
        <li v-for="item in weatherList">
          <div class="info_type">
            <span class="iconfont">{{item.type}}</span>
          </div>
          <div class="info_temp">
            <b>{{item.low}}</b>
            ~
            <b>{{item.high}}</b>
          </div>
          <div class="info_date"><span>{{item.date}}</span></div>
        </li>
      </ul>
    </div>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <!-- 官网提供的 axios 在线地址 -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <!-- 自己的js -->
    <script src="./js/main.js"></script>
  </body>
</html>

D:\Project\vscode\vue_text\查询天气案例\js\main.js

/**
 * 
 *  请求地址:http://wthrcdn.etouch.cn/weather_mini
    请求方法:get
    请求参数:city (要查询的城市名称)
    响应内容:天气信息
 */

var VM = new Vue({
  el: "#app",
  data: {
    city: "",
    //定义数组保存 天气信息
    weatherList: [],
  },
  //编写查询天气的方法
  methods: {
    searchWeather: function () {
      console.log("天气查询");
      console.log(this.city);

      var that = this;

      //调用接口
      axios.get("http://wthrcdn.etouch.cn/weather_mini?city=" + this.city).then(
        function (resp) {
          console.log(resp.data.data.forecast);
          //获取天气信息 保存到weatherList
          that.weatherList = resp.data.data.forecast;
        },
        function (error) {}
      );
    },
  },
});

computed 计算属性

 通过计算获取到的属性
 computed的作用:减少运算次数,缓存运算结果,运用于重复相同的计算。

函数和computed(计算属性)的区别?

  1. 定义函数也可以实现与 计算属性相同的效果,都可以简化运算。
  2. 不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=<device-width>, initial-scale=1.0" />
    <title>Document</title>
    <style>
      /*
        1.计算属性可以 减少运算次数,用于重复相同的计算
        2.定义函数也可以实现与计算属性相同的效果,但是计算属性可以简化运算
      */
    </style>
  </head>
  <body>
    <div id="app">
      <!-- <h1>{{a*b}}</h1>
      <h1>{{a*b}}</h1> -->
      <!-- 
      <h1>{{res()}}</h1>
      <h1>{{res()}}</h1> -->

      <h1>{{res2}}</h1>
      <h1>{{res2}}</h1>
    </div>
  </body>
  <script src="./js/vue.min.js"></script>
  <script>
    var VM = new Vue({
      el: "#app",
      data: {
        a: 10,
        b: 20,
      },
      methods: {
        res: function () {
          console.log("res方法执行了! !");
          return this.a + this.b;
        },
      },
      //使用计算属性 进行优化,减少运算次数,用于重复的运算
      computed: {
        res2: function () {
          console.log("res2方法执行了! !");
          return this.a + this.b;
        },
      },
    });
  </script>
</html>

过滤器

 过滤器是对即将显示的数据做进一步的筛选处理,然后进行显示,值得注意的是过滤器并没有改变原来的数据,只是在原数据的基础上产生新的数据。
 数据加工车间,对值进行筛选加工

  1. 过滤器常用来处理文本格式化的操作。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
  2. 过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示

过滤器使用位置

  1. 双括号插值内
{{ msg | filterA }} msg是需要处理的数据, filterA是过滤器, | 这个竖线是管道,通过这个管道将数据传输给过滤器进行过滤 加工操作
  1. v-bind绑定的值的地方。
<h1 v-bind:id=" msg | filterA"> {{ msg }} </h1>

局部过滤器

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
</head>

<body>
    <div id="app">
        <!-- 使用插值表达式,调用过滤器 -->
        <p>电脑价格: {{price | addIcon}}</p>
    </div>
</body>
<script src="./js/vue.min.js"></script>
<script>
    //局部过滤器 在vue实例的内部创建filter
    var VM = new Vue({
        //挂载点
        el: "#app",
        //model
        data: {

            price: 200,
        },
        //方法
        methods: {

        },
        //计算属性
        computed: {

        },
        //局部过滤器
        filters: {
            //定义处理函数 value = price
            addIcon(value) {
                return "$" + value;
            },
        },
    });
</script>

</html>

全局过滤器

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      /*
        需求: 将用户名开头字母大写
        总结:
          1.过滤器经常被用来处理文本格式化操作
          2.过滤器使用的两个位置: {{}} 插值表达式中, v-bind表达式中
          3.过滤器是通过管道传输数据的 |
      */
    </style>
  </head>
  <body>
    <div id="app">
      <p>{{user.name | changeName}}</p>
    </div>
  </body>
  <script src="./js/vue.min.js"></script>
  <script>

    //在创建vue实例之前,创建全局过滤器
    Vue.filter("changeName", function (value) {
      //将姓名的开头字母大写
      return value.charAt(0).toUpperCase() + value.slice(1);
    });

    var VM = new Vue({
      el: "#app",
      data: {
        user: { name: "jack" },
      },
    });

   
  </script>
</html>

watch(监听器)

 Vue.js 提供了一个方法 watch,它用于观察Vue实例上的数据变动。
 作用: 当你有一些数据需要随着其它数据变动而变动时,可以使用侦听属性

案例: 计数器

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <h2>计数器:{{count}}</h2>
      <input type="button" @click="count++" value="点我+1" />
    </div>
  </body>
  <script src="./js/vue.min.js"></script>
  <script>
    var VM = new Vue({
      el: "#app",
      data: {
        count: 1,
      },
      watch: {
        //监测属性的值的变化
        count: function (nval, oval) {
          //参数1:原来的值 参数2:新的值
          alert("计数器发生变化: " + oval + " 变化为 " + nval);
        },
      },
    });
  </script>
</html>

案例: 监听姓名变化,实时显示

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
</head>

<body>
    <div id="app">
        <label>名:<input type="text" v-model="fristName" /></label>
        <label>姓:<input type="text" v-model="lastName" /></label> {{fullName}}
    </div>
</body>
<script src="./js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el: "#app",
        data: {
            fristName: "",
            lastName: "",
            fullName: "",
        },
        //侦听器
        watch: {
            fristName: function(nval, oval) {
                //参数 1.新值,2.旧值
                this.fullName = nval + " " + this.lastName;
            },
            lastName: function(nval, oval) {
                this.fullName = this.fristName + " " + nval;
            },
        },
    });
</script>

</html>

组件化开发

 组件(Component)是自定义封装的功能。在前端开发过程中,经常出现多个网页的功能是重复的,而且很多不同的页面之间,也存在同样的功能。
 我们将相同的功能进行抽取,封装为组件,这样,前端人员就可以在组件化开发时,只需要书写一次代码,随处引入即可使用。
 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树
 vue的组件有两种:全局组件、局部组件

组件类型

  • 通用组件(例如表单、弹窗、布局类等)
  • 业务组件(抽奖、机器分类)
  • 页面组件(单页面开发程序的每个页面的都是一个组件、只完成功能、不复用)

组件开发三步曲
 声明、注册、使用

全局组件

语法格式

  1. 组件名以小写开头,采用短横线分割命名: 例如 hello-Word
  2. 组件中的data 必须是一个函数,注意与Vue实例中的data区分
  3. 在template模板中, 只能有一个根元素
Vue.component("组件名称", {
	template: "html代码", // 组件的HTML结构代码
	data(){ //组件数据
		return {}
	},
	methods: { // 组件的相关的js方法
		方法名(){
			// 逻辑代码
		}
	}
})

示例代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
</head>

<body>
    <div id="app">
        <!-- 使用组件 -->
        <lagou-header></lagou-header>
        <lagou-header></lagou-header>
        <lagou-header></lagou-header>
    </div>
</body>
<script src="./js/vue.min.js"></script>
<script>
    //定义全局组件
    //组件的命名规则: 一般用短横线进行连接,左边是公司名 右边组件的作用名称
    Vue.component("lagou-header", {
        template: "<div>HTML <h1 @click='hello'>{{msg}}</h1> </div>", //template模板中 只能有一个根元素
        //组件中的data是一个函数
        data() {
            return {
                msg: "这lagou-header是组件中的数据部分",
            };
        },
        methods: {
            hello() {
                alert("你好");
            },
        },
    });

    var VM = new Vue({
        el: "#app",
        data: {},
        methods: {},
    });
</script>

</html>

局部组件

 相比起全局组件,局部组件只能在同一个实例内才能被调用。局部组件的写法和全局组件差不多。 唯一不同就是:局部组件要写在Vue实例里面。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
</head>

<body>
    <div id="app">
        <web-msg></web-msg>
        <web-msg></web-msg>
        <web-msg></web-msg>
    </div>
</body>
<script src="./js/vue.min.js"></script>
<script>
    //创建局部组件
    var VM = new Vue({
        el: "#app",
        components: {
            //组件名
            "web-msg": {
                template: "<div><h1>{{msg1}}</h1><h1>{{msg2}}</h1></div>",
                data() {
                    return {
                        msg1: "开发ing...",
                        msg2: "开发完成!"
                    }
                },
            }
        }

    })
</script>

</html>

组件与模板分离

 由于把html语言写在组件里面很不方便,也不太好看所以将它们分开写。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <!-- 使用组件 -->
      <web-msg></web-msg>
    </div>

    <!-- 将模板写在 HTML中,给模板一个id -->
    <template id="t1">
      <div>
        <button @click="show">{{msg}}</button>
      </div>
    </template>
  </body>
  <script src="./js/vue.min.js"></script>
  <script>
    var VM = new Vue({
      el: "#app",
      components: {
        "web-msg": {
          template: "#t1",
          data() {
            return {
              msg: "点击查询",
            };
          },
          methods: {
            show() {
              alert("正在查询,请稍后...");
            },
          },
        },
      },
    });
  </script>
</html>

Vue生命周期

Vue生命周期

示例代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <h2 id="msg">{{message}}</h2>
      <button @click="next">获取下一句</button>
    </div>
  </body>
  <script src="./js/vue.min.js"></script>
  <script>
    var VM = new Vue({
      el: "#app",
      data: {
        message: "想当年,金戈铁马",
      },
      methods: {
        show() {
          alert("show方法执行了!");
        },
        next() {
          this.message = "气吞万里如虎!";
        },
      },
      // beforeCreate() {
      //   alert("1.beforeCreate函数,在Vue对象实例化之前执行");
      //   console.log(this.message); //undefined
      //   this.show(); //this.show is not a function
      // },
      // created() {
      //   alert("2.created函数执行时,组件的实例化完成,但是DOM页面还未生成")
      //   console.log(this.message);
      //   this.show();
      // },
      // beforeMount() {
      //   alert(
      //     "3.beforeMount函数执行时,模板已经在内存中编辑完成了,但是还没有被渲染到页面中"
      //   );
      //   console.log(
      //     "页面显示的内容" + document.getElementById("msg").innerText
      //   );
      //   console.log("data中的数据: " + this.message);
      // },
      // mounted() {
      //   alert("4.mounted函数执行时,模板已经被渲染到页面,执行完就会显示页面");
      //   console.log(
      //     "页面显示的内容" + document.getElementById("msg").innerText
      //   );
      // },
      // beforeUpdate() {
      //   alert("5.beforeUpdate执行时,内存中的数据已经更新,但是还没有渲染到页面");
      //   console.log(
      //     "页面显示的内容" + document.getElementById("msg").innerText
      //   );
      //   console.log("data中的数据: " + this.message);
      // },
      updated() {
        alert("6.updated执行时,内存中的数据已经更新,此方法执行完显示页面");
        console.log(
          "页面显示的内容" + document.getElementById("msg").innerText
        );
        console.log("data中的数据: " + this.message);
      },
    });
  </script>
</html>

Router

 在Web开发中,路由是指根据URL分配到对应的处理程序。 路由允许我们通过不同的 URL 访问不同的内容。
 通过 Vue.js 可以实现多视图单页面web应用(single page web application,SPA)

SPA

 单页面Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。
 单页应用不存在页面跳转,它本身只有一个HTML页面。我们传统意义上的页面跳转在单页应用的概念下转变为了 body 内某些元素的替换和更新,举个例子:

 整个body的内容从登录组件变成了欢迎页组件, 从视觉上感受页面已经进行了跳转。但实际上,页面只是随着用户操作,实现了局部内容更新,依然还是在index.html 页面中。
 单页面应用的好处:
 1. 用户操作体验好,用户不用刷新页面,整个交互过程都是通过Ajax来操作。
 2. 适合前后端分离开发,服务端提供http接口,前端请求http接口获取数据,使用JS进行客户端渲染。

单页面应用的好处:

  1. 用户操作体验好,用户不用刷新页面,整个交互过程都是通过Ajax来操作。
  2. 适合前后端分离开发,服务端提供http接口,前端请求http接口获取数据,使用JS进行客户端渲染。

路由相关的概念

组件名称功能作用
router是Vue.js官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用(SPA)变得易如反掌 ,router 就相当于一个管理者,它来管理路由。
routerouter相当于路由器, route就相当于一条路由.比如: Home按钮 => home内容, 这是一条route,news按钮 => news内容, 这是另一条路由。
routes是一组路由,把上面的每一条路由组合起来,形成一个数组。[{home 按钮 =>home内容 }, {about按钮 => about 内容}]
router-link组件router-link 是一个组件,是对标签的一个封装. 该组件用于设置一个导航链接,切换不同 HTML内容。 to 属性为目标地址, 即要显示的内容
router-view 组件路由导航到指定组件后,进行渲染显示页面

使用路由

  1. Vue.js 路由需要载入 vue-router 库
//方式1: 本地导入
<script src="vue-router.min.js"></script>
//方式2: CDN
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  1. 使用步骤
  1. 定义路由所需的组件
  2. 定义路由 每个路由都由两部分 path (路径) 和component (组件)
  3. 创建router路由器实例 ,管理路由
  4. 创建Vue实例, 注入路由对象, 使用$mount() 指定挂载点

 Vue 的$mount()为手动挂载,在项目中可用于延时挂载(例如在挂载之前要进行一些其他操作、判断等), 之后要手动挂载上。new Vue时,el和$mount并没有本质上的不同。

示例代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
        /*
        1.router 是VUE中路由管理器对象,用来管理路由
        2.route 是路由对象,一个路由就对应了一条访问路径,一组路由用 routes
        3.每个路由对象,都有两部分: path路径, component组件
        4.router-link 是对a标签的封装,通过to属性 指定链接
        5.router-view 路由访问到指定的组件,进行页面展示
      */
    </style>
</head>

<body>
    <div id="app">
        <h1>渣浪.com</h1>

        <p>
            <!-- 添加超链接, router-link 组件来进行导航, to属性指定链接 -->
            <router-link to="/home">go to home</router-link>
            <router-link to="/news">go to news</router-link>
        </p>

        <!-- 路由的出口, 路由匹配到组件之后,要渲染到这里 -->
        <router-view></router-view>
    </div>
</body>
<!-- 导入vue 与 router库 -->
<script src="./js/vue.min.js"></script>
<script src="./js/vue-router.min.js"></script>
<script>
    //1.定义路由所需的组件
    const home = {
        template: "<div>首页</div>"
    };
    const news = {
        template: "<div>新闻</div>"
    };

    //2.定义路由 每个路由有两部分 path(路径),component(组件)
    const routes = [{
        path: "/home",
        component: home
    }, {
        path: "/news",
        component: news
    }, ];

    //3.创建路由管理器实例
    const router = new VueRouter({
        routes: routes,
    });

    //4.创建Vue实例 ,将router注入到 vue实例中,让整个应用都拥有路由的功能
    var VM = new Vue({
        router,
    }).$mount("#app"); //代替el
</script>

</html>

Node.js

 传统意义上的 JavaScript 运行在浏览器上,Chrome 使用的 JavaScript 引擎是 V8,Node.js 是一个运行在服务端 的框架,它的底层就使用了 V8 引擎,这样就可以使用javascript去编写一些服务端的程序,这样也就实现了用 javaScript去开发 Apache + PHP 以及 Java Servlet所开发的服务端功能,这样做的好处就是前端和后端都采用 javascript,即开发一份js程序即可以运行在前端也可以运行的服务端,这样比一个应用使用多种语言在开发效率上 要高,不过node.js属于新兴产品,一些公司也在尝试使用node.js完成一些业务领域,node.js基于V8引擎,基于事件驱动机制,在特定领域性能出色,比如用node.js实现消息推送、状态监控等的业务功能非常合适

安装node.js

  1. 下载对应你系统的Node.js版本 https://nodejs.org/en/download/
  2. 选安装目录D:\Tools\nodejs
  3. 测试: 在命令提示符下输入命令
    C:\Users\chao1>node -v
    v18.13.0
    

NPM

 npm全称Node Package Manager,他是node包管理和分发的工具,使用NPM可以对应用的依赖进行管理,NPM 的功能和服务端项目构建工具maven的依赖管理功能差不多,我们通过npm 可以很方便地下载js库,打包js文件。

node.js已经集成了npm工具
 在命令提示符输入 npm -v 可查看当前npm版本

npm -v

查看包管理路径
 包路径就是npm从远程下载的js包所存放的路径。 使用 npm confifig ls 查询NPM管理包路径(NPM下载的依赖包所存放的路径)

C:\Users\chao1>npm config ls
; "builtin" config from D:\Tools\nodejs\node_modules\npm\npmrc

prefix = "C:\\Users\\chao1\\AppData\\Roaming\\npm"

; node bin location = D:\Tools\nodejs\node.exe
; node version = v18.13.0
; npm local prefix = C:\Users\chao1
; npm version = 8.19.3
; cwd = C:\Users\chao1
; HOME = C:\Users\chao1
; Run `npm config ls -l` to show all defaults.

设置包管理路径
 依赖包放在C盘不太合适,为了方便对依赖包管理, 我们将管理包的路径设置在单独的地方:

  1. 我们选择一个路径,专门存放这些依赖包.我选择创建一个目录: H:\software\nodejs_package
  2. 在 H:\software\nodejs_package 下再创建 npm_modules 文件夹 和 npm_cache 文件夹:
mkdir D:\Tools\nodejs\npm_modules
mkdir D:\Tools\nodejs\npm_cache
  1. 执行下边的命令,设置为自定义的包管理路径:
npm config set prefix "D:\Tools\nodejs\npm_modules"
npm config set cache "D:\Tools\nodejs\npm_cache"
  1. 此时再使用 npm confifig ls 查询NPM管理包路径发现路径已更改

NPM环境变量配置

  1. 查看npm的全局路径是什么
D:\Tools\nodejs>npm config get prefix
D:\Tools\nodejs\npm_modules
  1. 配置PATH环境变量
* 添加新的系统变量: key=NODE_HOME , value= H:\software\nodejs_package
* path中添加 %NODE_HOME%\npm_modules

安装cnpm
 npm默认会去国外的镜像去下载js包,在开发中通常我们使用国内镜像,这里我们使用淘宝镜像下边我们来安装cnpm: 有时我们使用npm下载资源会很慢,所以我们可以安装一个cnmp(淘宝镜像)来加快下载速度。

  1. 联网情况下, 输入命令,进行全局安装淘宝镜像:
//安装
npm install -g cnpm --registry=https://registry.npm.taobao.org

//查看cnpm的版本
cnpm -v

Vue-cli

 Vue cli是基于Vue的应用开发提供的一个标准的脚手架工具.为应用搭建基础的框架结构,提供插件、开发服务、Preset、构建打包功能Vue cli 背后集成了现代化开发的诸多功能,通过简单的命令就可以完成 "零配置"的项目环境搭建
 在安装vue-cli前,要确认自己的电脑是否安装了nodejs和npm

安装vue-cli
 目前主流版本是 2.x 和 3.x 版本,安装3.x 以上的版本是因为该版本既可以创建2.x项目与3.x 项目

  1. 安装命令
注意: 以管理员身份打开命令行
npm install -g @vue/cli
  1. 输入 vue命令
C:\Windows\System32>vue -V
@vue/cli 5.0.8

快速构建Vue项目

  1. 创建目录
D:\Project\vuecli_work
  1. cmd进入目录执行下面的命令,基于交互式命令方式,创建项目
//文件名 不支持驼峰(含大写字母)使用短横线方式
vue create my-project
  1. 执行下面的命令
$ cd my-project
$ npm run serve
  App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.31.196:8080/

导入Vue项目到VSCode

  1. VSCode中右键选择打开文件夹
  2. 选择桌面上的项目
  3. 打开项目,可以看到如下项目结构

项目结构介绍

Vue脚手架自定义配置

package.json

 每个项目的根目录下面,一般都有一个 package.json 文件,定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。 npm install 命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。
 注意: 不推荐这种方式,因为package.json 主要是用来管理包的配置信息.为了方便维护,我们将Vue脚手架相关的配置单独定义到 vue.confifig.js 配置文件中

{
    //1.项目基本信息
    "name": "my-project",
    "version": "0.1.0",
    "private": true,
    //2.指定运行脚本命令
    "scripts": {
        "serve": "vue-cli-service serve",
        "build": "vue-cli-service build"
    },
    //4.生产环境所依赖模块的版本
    "dependencies": {
        "core-js": "^3.8.3",
        "vue": "^2.6.14",
        "vue-router": "^3.5.1"
    },
    //5.本地环境开发所依赖的版本
    "devDependencies": {
        "@vue/cli-plugin-babel": "~5.0.0",
        "@vue/cli-plugin-router": "~5.0.0",
        "@vue/cli-service": "~5.0.0",
        "vue-template-compiler": "^2.6.14"
    }
}

通过package.json 配置项目
 配置说明: 该配置设置打包时服务器相关的信息,port : 访问端口,open true: 打包完成自动打开浏览器

"vue": {
        "devServer": {
            "port": "8888",
            "open": true
        }
    }

启动项目

  1. 在VSCode中选择项目,右键在终端打开
  2. 输入命令
npm rum serve

单独的配置文件配置项目 vue.config.js

  1. 在项目的根目录创建文件 vue.config.js
  2. 删除掉package中新添加的配置项.
  3. 在vue.config.js 文件中进行相关配置
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
    transpileDependencies: true,
    devServer: {
        open: true,
        port: 8889
    }
})

组件化开发

 组件化是Vue的精髓,Vue项目就是由一个一个的组件构成的。 我们主要的工作就是开发的组件.

组件介绍

  1. 我们用 vue-cli 脚手架搭建的项目,里面有很多,如 index.vue 或者 App.vue 这一类的文件。每一个*.vue 文件都是一个组件 ,是一个自定义的文件类型, 比如 App.vue 就是整个项目的根组件。

常见的组件

组件类别功能描述
页面级别的组件页面级别的组件,通常是 views 目录下的.vue组件,是组成整个项目的各个主要页面
业务上可复用的基础组件这一类组件通常是在业务中被各个页面复用的组件,这一类组件通常都写到 components 目录下,然后通过import在各个页面中使用

组件的组成部分

组件的组成部分功能描述
template组件的HTML部分
script组件的JS脚本 (使用ES6语法编写)
style组件的CSS样式
<!-- 1.template 代表html结构, template中的内容必须有且只有一个根元素
编写页面静态部分 就是 view部分 -->
<template>
    <div>
        测试页面...
    </div>
</template>

<!-- 2.编写vue.js代码 -->
<script>
    //可以导入其组件
    // import Header from '../components/header.vue'
    
    //默认写法, 输出该组件
    export default {
        name:"Home", // 组件名称,用于以后路由跳转
        data() {// 当前组件中需要使用的数据
            return {}
        },
        methods: {}
    }
</script>

<!-- 编写当前组件的样式代码 -->
<style scoped>
    /* 页面样式 加上scoped 表示样式就只在当前组件有效*/
</style>

项目运行流程

  1. main.js
     项目运行 会加载入口文件 main.js
/*
html文件中,通过script src = 'xxx'标签引入js文件。而vue中,通过 import 变量名 from 文件路径 的方式导入文件,不光可以导入js文件。
	1.变量名: 指的是为导入的文件起一个名称,不是指导入的文件的名称,相当于变量名。
	2.文件路径: 指的是文件的相对路径
*/

import Vue from 'vue'
import App from './App.vue'  //主组件
import router from './router'  //路由

//关闭启动提示
Vue.config.productionTip = false

//创建Vue实例
new Vue({
	router, //为整个项目添加路由
	render: h => h(App) //这是一个函数ES6语法,作用是生成模板: App = App.vue
}).$mount('#app') //挂载的是App.vue组件中的id为app的区域
  1. App.vue
     App.vue 是vue项目的主组件,是页面入口文件 ,所有页面都是在App.vue下进行切换的
App.vue 中的模板(HTML代码)
<template>
	<div id="app"> 挂载的是这个div
		<div id="nav">
			这里是两个路由导航链接
			1. to="/" 项目根路径 跳转的是首页
			<router-link to="/">Home</router-link> |
			2. to="/about" 点击About按钮,跳转到about组件
			<router-link to="/about">About</router-link>
		</div>
		router-view 的作用是 根据访问的路径,渲染路径匹配到的视图组件
		<router-view/>
	</div>
</template>
  1. router路由
     找到路由文件,来看一下具体的路由配置
// 引入所需文件
import Vue from 'vue'	//vue库
import VueRouter from 'vue-router'	//vue-router库
import HomeView from '../views/HomeView.vue'		//首页

//使用路由功能
Vue.use(VueRouter)

//创建路由规则
const routes = [
  {
    path: '/',	//路径
    name: 'home',	//名称
    component: HomeView	//组件HomeView.vue
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')  //ES6的另外一种写法
  }
]

//创建路由管理器,管理routes
const router = new VueRouter({
  routes
})

//export 用来导出模块 router就代表了整个路由文件
export default router
  1. HomeView.vue组件
     默认访问的是HomeView.vue首页,D:\Project\vuecli_work\my-project\src\views\HomeView.vue
//视图部分
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
// @符号代表 src目录
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  components: { //在Homeview组件中引入了HelloWorld组件
    HelloWorld
  }
}
</script>

D:\Project\vuecli_work\my-project\src\components\HelloWorld.vue 组件页面

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>
      For a guide and recipes on how to configure / customize this project,<br>
      check out the
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
    </p>
    <h3>Installed CLI Plugins</h3>
    <ul>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
    </ul>
    <h3>Essential Links</h3>
    <ul>
      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
    </ul>
    <h3>Ecosystem</h3>
    <ul>
      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

自定义组件

 创建Header.vue组件

  1. 在components 目录下创建 Header.vue
  2. 编写Header.vue
<template>
    <div class="header">{{msg}}</div>
</template>

<script>
//JS部分
export default {
    name: "Header", //组件的名称
    data() {        //data函数
        return {
            msg:"这是一个Header组件"
        }
    },
}

</script>

//scoped 表示当前的样式只作用于当前组件中的template
<style scoped>
.header {
    height: 100px;
    line-height: 100px;
    background-color: blue;
    text-align: center;
    color: brown;
}
</style>
  1. 引入Header组件
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
    <Header></Header>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import Header from '@/components/Header.vue'

export default {
  name: 'HomeView',
  components: { 
    HelloWorld,
    Header
  }
}
</script>

组件的传参

 props : 是组件中的属性, 表示组件可以接受参数

定义Header.vue属性

<template>
    <div class="header">{{msg}}</div>
</template>

<script>
//JS部分
export default {
    name: "Header", //组件的名称
    data() {        //data函数
        return {
            msg2:"这是一个Header组件"
        }
    },
    props:['msg']
}

</script>

//scoped 表示当前的样式只作用于当前组件中的template
<style scoped>
.header {
    height: 100px;
    line-height: 100px;
    background-color: blue;
    text-align: center;
    color: brown;
}
</style>

引用Header.vue组件并传递参数

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
    <Header msg="这是通过props属性进行赋值显示出来的"></Header>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import Header from '@/components/Header.vue'

export default {
  name: 'HomeView',
  components: { 
    HelloWorld,
    Header
  }
}
</script>

Element-UI

 element-ui 是饿了么前端出品的基于 Vue.js的 后台组件库,方便程序员进行页面快速布局和构建
 Element-UI官方站点:https://element.eleme.cn/#/zh-CN

Element-UI使用

  1. 创建 一个新的VUE项目
D:\Project\vuecli_work>vue create el-project02
D:\Project\vuecli_work>cd el-project02
D:\Project\vuecli_work\el-project02>npm run serve
  1. 当前项目下打开终端, 安装依赖包 ,执行下面的命令(管理员)
PS D:\Project\vuecli_work\el-project02> npm i element-ui -S
  1. 打开 main.js , 导入Element-UI 相关资源.
     main.js是工程的入口文件,在此文件中加载了很多第三方组件,如:Element-UI、Base64、VueRouter等。
import Vue from 'vue'
import App from './App.vue'
import router from './router'

//导入组件库
import ElementUI from 'element-ui'
//导入组件相关样式
import 'element-ui/lib/theme-chalk/index.css'
//配置Vue插件 将El安装到Vue上
Vue.use(ElementUI);

Vue.config.productionTip = false

new Vue({
    router,
    render: h => h(App)
}).$mount('#app')

Vue-CLI工程改造

  1. 删除components 目录下的 HelloWord.vue组件
  2. 删除App.vue中的部分内容,只保留如下部分
<template>
  <div id="app">
  </div>
</template>

<style>
</style>
  1. 删除router文件下的路由文件 index.js部分内容,只保留如下部分
import Vue from 'vue'
import VueRouter from 'vue-router'
// import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter)

const routes = []

const router = new VueRouter({
    routes
})
export default router
  1. 删除views目录下的 About.vue 与 Home.vue

安装axios

  1. npm安装:使用npm下载axios包
PS D:\Project\vuecli_work\el-project02> npm i axios
  1. 在main.js文件中导入axios 相关资源
//引入axios
import axios from 'axios'
//Vue对象使用axios
Vue.prototype.axios = axios;

用户登录界面制作

创建login.vue 组件

  1. 在components 下创建Login.vue
  2. 将Diglog组件的内容,拷贝到Login.vue,进行修改:
<template>
<!-- Form -->
<el-dialog title="用户登录" :visible.sync="dialogFormVisible">
  
  <el-form>
    <el-form-item label="用户名称" :label-width="formLabelWidth">
      <el-input autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="用户密码" :label-width="formLabelWidth">
      <el-input autocomplete="off"></el-input>
    </el-form-item>
  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button type="primary" @click="dialogFormVisible = false">登 录</el-button>
  </div>
</el-dialog>

</template>

<script>
export default {
    data() {
        return {
        dialogTableVisible: false,
        dialogFormVisible: false,
        formLabelWidth: '120px'
      };
    }
}
</script>

<style scoped>
</style>

配置路由
D:\Project\vuecli_work\el-project02\src\router\index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

//导入Login.vue组件
import Login from "@/components/Login.vue"

Vue.use(VueRouter)

const routes = [
    //根/路径跳转
    {
        path: "/",
        redirect: "login", //重定向到login
    },
    //登录路由
    {
        path: "/login",
        name: "login",
        component: Login
    }
];

const router = new VueRouter({
    routes
})
export default router

修改App.vue

<template>
  <div id="app">
    <!-- 根据访问路径,渲染路径匹配到的组件 -->
    <router-view></router-view>
  </div>
</template>

编写登录功能

  1. 去掉关闭按钮, 添加一个属性 :show-close="false"

<el-dialog title="用户登录" :show-close="false" :visible.sync="dialogFormVisible">

  1. 修改登陆触发事件

<el-button type="primary" @click="login">登 录</el-button>

  1. 双向数据绑定

data中定义数据
Login.vue

data() {
        return {
            dialogFormVisible: true,    //是否可见
            formLabelWidth: '120px',    //宽度
            user: { username: "", password: "" }, //登录数据
        };
    },

使用 v-model, 将视图与模型进行绑定

<el-form>
    <el-form-item label="用户名称" :label-width="formLabelWidth">
      <el-input v-model="user.username" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="用户密码" :label-width="formLabelWidth">
      <el-input v-model="user.password" autocomplete="off"></el-input>
    </el-form-item>
  </el-form>
  1. 编写login方法
methods:{
        login() {
        //定义常量保存url
        const url = "http";

        //发送请求
        this.axios
            .get(url,{
                //携带参数
                params: {
                    username: this.user.username,
                    password: this.user.password,
                },
            })
            .then((res)=>{
                console.log();
                //成功就将对话框关闭
                this.dialogFormVisible = false;
            })
            .catch((error) => {
                //出现错误使用ElementUI提供的消息提示
                this.$message.error("对不起!登录错误!");
            })

        }

    }

Postman搭建mock server

 Mock server就是模拟一个服务器,我们使用Mock server可以模拟后台接口,对请求进行响应.
 在前后端分离的开发中 前端利用mockeserver模拟出对应接口,拿到返回数据来调试,无需等后端开发人员完成工作。

修改请求的URL

//定义常量保存url
        const url = "https://82a0bbc8-ce71-4ba3-82f6-c07e938fda28.mock.pstmn.io/login";

登录成功后跳转

 在js中设置跳转,常用的一种方法是 this.$router.push

<template>
<!-- Form -->
<el-dialog title="用户登录" :show-close="false" :visible.sync="dialogFormVisible">
  
  <el-form>
    <el-form-item label="用户名称" :label-width="formLabelWidth">
      <el-input v-model="user.username" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="用户密码" :label-width="formLabelWidth">
      <el-input v-model="user.password" autocomplete="off"></el-input>
    </el-form-item>
  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button type="primary" @click="login">登 录</el-button>
  </div>
</el-dialog>

</template>

<script>
export default {
    data() {
        return {
            dialogFormVisible: true,    //是否可见
            formLabelWidth: '120px',    //宽度
            user: { username: "", password: "" }, //登录数据
        };
    },
    methods:{
        login() {
        //定义常量保存url
        const url = "https://82a0bbc8-ce71-4ba3-82f6-c07e938fda28.mock.pstmn.io/login";

        //保存this,回调函数里面使用,使用箭头函数=>就可以使用this
        //var that = this;

        //发送请求
        this.axios
            .get(url,{
                //携带参数
                params: {
                    username: this.user.username,
                    password: this.user.password,
                },
            })
            .then((res)=>{
                console.log(res.data);
                alert("登录成功");
                //成功就将对话框关闭
                this.dialogFormVisible = false;
                //跳转页面,前端跳转页面必须使用路由,使用$router对象中的push方法
                this.$router.push('/index');
            })
            .catch((error) => {
                //出现错误使用ElementUI提供的消息提示
                this.$message.error("对不起!登录错误!");
            })

        }

    }

}
</script>

<style scoped>
</style>

首页布局页面制作

创建 index.vue
D:\Project\vuecli_work\el-project02\src\components\Index.vue

<template>
    <el-button type="danger">布局页面</el-button>
</template>

<script>

</script>

<style scoped>
</style>

配置路由
 router目录下 的index.js 路由文件 D:\Project\vuecli_work\el-project02\src\router\index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

//导入Login.vue组件
import Login from "@/components/Login.vue"

//导入布局组件
import Index from "@/components/Index.vue"

Vue.use(VueRouter)

const routes = [
    //根/路径跳转
    {
        path: "/",
        redirect: "login", //重定向到login
    },
    //登录路由
    {
        path: "/login",
        name: "login",
        component: Login
    },
    //布局路由
    {
        path: '/index',
        name: 'index',
        component: Index
    }
];

const router = new VueRouter({
    routes
})
export default router

布局容器element-ui

 Container 布局容器 ,是用于布局的容器组件,方便快速搭建页面的基本结构:

  1. 在官方文档中找到布局的容器代码, 复制到 Index.vue
<template>
<div>
    <el-container>
        <el-header>Header</el-header>
        <el-container>
            <el-aside width="200px">Aside</el-aside>
            <el-main>Main</el-main>
        </el-container>
    </el-container>
</div>
</template>

<script>
 
</script>

<style scoped>
.el-container {
    height: 725px;
}
.el-header, .el-footer {
    background-color: #B3C0D1;
    color: #333;
    text-align: center;
    line-height: 60px;
  }
  
  .el-aside {
    background-color: #D3DCE6;
    color: #333;
    text-align: center;
    line-height: 200px;
  }
  
  .el-main {
    background-color: #E9EEF3;
    color: #333;
    text-align: center;
    line-height: 160px;
  }
</style>
  1. 拷贝布局容器中的导航菜单代码, 进行修改,代码如下
<template>
  <div>
    <el-container>
      <el-header>后台管理</el-header>
      <el-container>
        <!-- 侧边栏 -->
        <el-aside width="200px">
          <el-menu
            default-active="2"
            class="el-menu-vertical-demo"
            background-color="#d3dce6"
          >
            <el-submenu index="1">
              <template slot="title">
                <i class="el-icon-location"></i>
                <span>导航菜单</span>
              </template>
              <el-menu-item-group>
                <el-menu-item index="1-1"><i class="el-icon-menu"></i>课程管理</el-menu-item>
              </el-menu-item-group>
            </el-submenu>
          </el-menu>
        </el-aside>
        <!-- 主要区域 -->
        <el-main>页面内容</el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script></script>

<style scoped>
.el-container {
  height: 725px;
}
.el-header,
.el-footer {
  background-color: #b3c0d1;
  color: #333;
  text-align: center;
  line-height: 60px;
}

.el-aside {
  background-color: #d3dce6;
  color: #333;
  text-align: center;
  line-height: 200px;
}

.el-main {
  background-color: #e9eef3;
  color: #333;
  text-align: center;
  line-height: 160px;
}
</style>

课程列表组件制作

 当我们点击导航菜单中的课程管理时,要显示课程信息

编写 Course.vue

D:\Project\vuecli_work\el-project02\src\components\Course.vue

<template>
    <el-button type="danger">课程信息</el-button>
</template>

<script>
export default {};
</script>

<style scoped>

</style>

配置路由

  1. 在index.js路由文件中, 为布局路由添加children 属性表示子路由
//导入课程组件
import Course from "@/components/Course.vue"

//布局路由
    {
        path: '/index',
        name: 'index',
        component: Index,
        //添加子路由,使用 children属性 来表示子路由
        children: [
            //课程信息子路由
            {
                path: "/course",
                name: "course",
                component: Course
            }
        ]
    }
  1. 修改 Index.vue组件中的导航菜单属性
     router表示是否使用 vue-router 的模式,启用该模式会在激活导航时以index作为path进行路由跳转
<el-menu
            default-active="2"
            class="el-menu-vertical-demo"
            background-color="#d3dce6"
            router 
          >
  1. 为index属性指定路由
<el-menu-item-group>
                <!-- 修改 index的路由地址 -->
                <el-menu-item index="/course">
                    <i class="el-icon-menu"></i>课程管理
                </el-menu-item>
              </el-menu-item-group>
  1. 设置路由的出口,将课程信息展示再main
<!-- 主要区域 -->
        <el-main>
            <router-view></router-view>
        </el-main>

Table表格组件

 我们通过table组件来实现一个课程页面展示的功能,通过查看Element-UI库,我们需要Table 表 格.进入Element-UI官方,找到Table组件,拷贝源代码到vue页面中(豹纹式表格)

添加表格组件
 复制表格组件相关的代码到 Course.vue中

<template>
    <el-table v-loading="loading" element-loading-text="数据加载中..." :data="courseList" stripe style="width: 100%">
        <el-table-column prop="id" label="ID" width="180">
        </el-table-column>
        <el-table-column prop="course_name" label="课程名称" width="180">
        </el-table-column>
        <el-table-column prop="price" label="价格">
        </el-table-column>
        <el-table-column prop="sort_num" label="排序">
        </el-table-column>
        <el-table-column prop="status" label="状态">
        </el-table-column>
    </el-table>
</template>

<script>
export default {
    data() {
        return {
            courseList: [
                {
                    id: 1,
                    course_name: "KOG权威指南",
                    price: 88.88,
                    sort_num: 1,
                    status:"上架"
                },
            ]
        }
    },

    //钩子函数,在DOM页面生成之前执行
    created() {
        //在页面生成之前, 调用loadCourse
        this.loadCourse();
        //访问后台接口,获取数据并返回
    },

    //方法集合
    methods: {
        //方法1:获取课程信息
        loadCourse() {
            //开启
            this.loading = true;
            //访问后台接口,获取数据并返回
            const url = "http://localhost:9090/lagou_edu_home/course";
            return this.axios
                .get(url,{
                    params:{
                        methodName:"findCourseList"
                    }
                }).then((res) => {
                    console.log(res.data);
                    //将获取到的数据赋值给 courseList
                    this.courseList = res.data;
                    this.loading = false;
                }).catch((error => {
                    this.$message.error("获取数据失败!");
                }));
        }
    }
};
</script>

<style scoped>

</style>

跨域问题解决

出现跨域问题
 当我们在前端项目中,向后端发送请求的获取课程数据的时候,出现了跨域问题
 已被CORS策略阻止:请求的资源上没有' Access-Control-Allow-Origin'标头(跨域请求失败)

Access to XMLHttpRequest at 'http://localhost:8080/lagou_edu_home/course?
methodName=findCourseList' from origin 'http://localhost:8088' has been blocked
by CORS policy: No 'Access-Control-Allow-Origin' header is present on the
requested resource.

什么是跨域
 跨域是指通过JS在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,只要协议、域名、端口有任何一个不同,都被当作是不同的域,浏览器就不允许跨域请求。

  • 跨域的几种常见情

解决跨域问题
 跨域的允许主要由服务器端控制。服务器端通过在响应的 header 中设置 Access-Control-Allow-Origin 及相关一系列参数,提供跨域访问的允许策略:

  • 设置响应头中的参数来允许跨域域请求:
    Access-Control-Allow-Credentials
    Access-Control-Allow-Origin 标识允许跨域的请求有哪些
    
  1. 在POM文件中引入依赖
<!-- 解决跨域问题所需依赖 -->
        <dependency>
            <groupId>com.thetransactioncompany</groupId>
            <artifactId>cors-filter</artifactId>
            <version>2.5</version>
        </dependency>
  1. 在web.xml中 配置跨域 fifilter

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--配置跨域过滤器-->
    <filter>
        <filter-name>corsFilter</filter-name>
        <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>corsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

数据库SQL脚本

数据库脚本下载

条件查询

ElementUI输入框组件

 Input 输入框通过鼠标或键盘输入字符

<template>
    <div>
        <!-- 条件查询 -->
        <el-row :gutter="20">
            <el-col :span="6">
                <el-input prefix-icon="el-icon-search" placeholder="课程名称" v-model="filter.course_name" clearable>
                </el-input>
            </el-col>
            <!-- 查询按钮 -->
            <el-col :span="1">
                <el-button type="primary" @click="search">点击查询</el-button>
            </el-col>
        </el-row>
        <el-table v-loading="loading" element-loading-text="数据加载中..." :data="courseList" stripe style="width: 100%">
            <el-table-column prop="id" label="ID" width="180">
            </el-table-column>
            <el-table-column prop="course_name" label="课程名称" width="180">
            </el-table-column>
            <el-table-column prop="price" label="价格">
            </el-table-column>
            <el-table-column prop="sort_num" label="排序">
            </el-table-column>
            <el-table-column prop="status" label="状态">
            </el-table-column>
        </el-table>
    </div>
</template>

完成根据课程名查询

  1. 双向数据绑定

Model 模型

data() {
        return {
            loading: false, //是否弹出加载提示
            courseList: [], //定义集合,保存从接口获取的参数
            filter: { course_name: "" } //查询条件
        };
    },

View 视图

<el-input prefix-icon="el-icon-search" placeholder="课程名称" v-model="filter.course_name" clearable>        
</el-input>
  1. 设置点击事件
<el-button type="primary" @click="search">点击查询</el-button>
  1. methods中添加方法
search() {
            //开启加载提示
            this.loading = true;
            //发送请求
            return this.axios
                .get("http://localhost:9090/lagou_edu_home/course", {
                    //携带参数
                    params: {
                        methodName: "findByCourseNameAndStatus",
                        course_name: this.filter.course_name
                    }
                })
                .then(res => {
                    console.log(res);
                    this.courseList = res.data;
                    //关闭加载
                    this.loading = false;
                })
                .catch(error => {
                    this.$message.error("获取数据失败!");
                });
        }

作者:Soulboy