IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 拉勾教育管理系统(前端) -> 正文阅读

[JavaScript知识库]拉勾教育管理系统(前端)

拉勾教育管理系统(前端)

Vue.js

Vue.js 介绍

Vue.js是什么?

1、Vue (读音 /vju?/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。

2、Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

3、自底向上逐层应用:作为渐进式框架要实现的目标就是方便项目增量开发(即插即用)。

4、官方网址:https://cn.vuejs.org/v2/guide/

为什么使用Vue?

1、声明式渲染: 前后端分离是未来趋势

2、渐进式框架: 适用于各种业务需求

3、简单易学: 国人开发,中文文档,不存在语言障碍,易于理解和学习

Vue.js 基础

Vue.js的使用

1、在html页面使用script引入vue.js的库即可使用

远程CDN
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
本地
<script src="vue.min.js"></script>

2、Vue-CLI脚手架:使用vue.js官方提供的CLI脚本架很方便去创建vue.js工程雏形

入门程序

创建一个vuetest目录,并且在目录下创建 01_vue入门程序.html 文件。

代码编写步骤:

1、定义html,引入vue.js

2、定义app div,此区域作为vue的接管区域

3、定义Vue实例,接管app区域

4、定义model(数据对象)

5、在app中展示数据

<!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.引入vue.js -->
    <!--第一种引入vue.js的CDN地址-->
    <!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> -->
    <!--第二种本地导入-->
    <script src="./js/vue.min.js"></script>

</head>
<body>
    <!-- 2.创建 id为app的div,将此区域作为vue接管的区域 -->
    <div id="app">
        <!--{{}}双括号是VUE中的差值表达式,可以获取Vue实例中的数据(data),将表达式的值输出到HTML页面-->
        {{name}}
    </div>
    
</body>

<script>
    // 3.创建Vue实例
    var VM = new Vue({
        // 定义Vue实例挂载的元素节点,表示vue接管该div
        el:"#app",
        // Vue中用到的数据,定义在data中,data中可以定义复杂数据
        data:{
            name:"Hello Vue!!",
        },
    });
</script>

</html>
{{}}: 插值表达式

插值表达式的作用?

? 通常用来获取Vue实例中定义的数据(data)

? 属性节点中不能够使用插值表达式

el: 挂载点

1、el的作用 ?

? 定义 Vue实例挂载的元素节点,表示vue接管该区域

2、Vue的作用范围是什么 ?

? Vue会管理el选项命中的元素,及其内部元素

3、el选择挂载点时,是否可以使用其他选择器 ?

? 可以,但是建议使用 ID选择器

4、是否可以设置其他的DOM元素进行关联 ?

? 可以但是建议选择DIV,不能使用HTML和Body标签

data: 数据对象

1、Vue中用到的数据定义在data中

2、data中可以写复杂类型

3、渲染复杂类型数据的时候,遵守js语法

<body>
    <!-- 2.创建 id为app的div,将此区域作为vue接管的区域 -->
    <div id="app">
        <!--{{}}双括号是VUE中的差值表达式,可以获取Vue实例中的数据(data),将表达式的值输出到HTML页面-->
        {{name}}<br>
        {{school.name}} {{school.mobile}}<br>
        <ul>
            <li>{{names[0]}}</li>
            <li>{{names[1]}}</li>
            <li>{{names[2]}}</li>
        </ul>
    </div>    
</body>

<script>
    // 3.创建Vue实例
    var VM = new Vue({
        // 定义Vue实例挂载的元素节点,表示vue接管该div
        el:"#app",
        // Vue中用到的数据,定义在data中,data中可以定义复杂数据
        data:{
            name:"Hello Vue!!",
            // 对象类型
            school:{
                name:"拉勾教育",
                mobile:"1001001",
            },
            // 数组类型
            names:["尼古拉斯","赵四","凯撒"]
        },
    });
</script>

声明式渲染的好处

Vue中的声明式渲染,简单理解就是我们声明数据,Vue帮我们将数据渲染到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>Document</title>
</head>
<body>
    <div id="app">
        <h2>{{name}}</h2>
    </div>
</body>

<!-- <script src="./js/jquery-1.8.3.min.js"></script>
<script>
    $(document).ready(function(){
        $("#app").append("<h2>Hello World! !</h2>")
    });
</script> -->

<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",  // 挂载点
        data:{
            name:"Hello World! !"
        },
    });
</script>
</html>

Vue常用指令

根据官网的介绍,指令是带有 v- 前缀的特殊属性。通过指令来操作DOM元素

1.v-text 指令

作用: 获取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>Document</title>
</head>
<body>
    <div id="app">
        <!-- 插值表达式 不会覆盖原来的内容体 -->
        <h2>{{message}}高薪训练营</h2>

        <!-- v-text 获取data数据,设置标签的内容,会覆盖之前的内容体 -->
        <h2 v-text="message">高薪训练营</h2>

        <!-- 拼接字符串 -->
        <h2 v-text="message+1"></h2>
        <h2 v-text="message+'abc'"></h2>
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        data:{
            message:"Java程序员"
        }
    });

</script>
</html>
2.v-html 指令

作用: 设置元素的 innerHTML (可以向元素中写入新的标签)

代码示例

<!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>
    <style>
        /*
        v-html指令:设置元素的innerHTML,向元素中写入标签
        */
    </style>
</head>
<body>
    <div id="app">
        <!-- 获取普通文本 -->
        {{message}}
        <h2 v-text="message"></h2>
        <h2 v-html="message"></h2>

        <!-- 设置元素的innerHTML -->
        <h2 v-html="url"></h2>
        <h2 v-text="url"></h2>
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        data:{
            message:"Java程序员",
            url:"<a href='https://www.baidu.com'>百度一下</a>"
        }
    });
</script>
</html>
3.v-on 指令

作用:为元素绑定事件,比如: v-on:click,可以简写为 @click=“方法”

绑定的方法定义在 VUE实例的method属性中

语法格式

<div id="app">
        <!-- 绑定点击事件 -->
        <input type="button" value="点击按钮" v-on:click="方法名">
        <!-- 简写方式 -->
        <input type="button" value="点击按钮" @click="show">
</div>
var VM = new Vue({
	el:"#app",
	data:{},
	// 通过method 专门存放vue的方法
	methods: {
		show:function(){
			alert("程序员在加班!!");
		},
	},
});

代码示例

<!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>
    <style>
        /*
            v-on指令:作业是为元素绑定事件
        */
    </style>
</head>
<body>
    <div id="app">
        <!-- 绑定点击事件 -->
        <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>
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        data:{
            food:"麻辣小龙虾"
        },
        // 通过method 专门存放vue的方法
        methods: {
            show:function(){
                alert("程序员在加班!!");
            },
            changeFood:function(){
                console.log(this.food);
                // 使用this获取data中的数据
                // 在vue中 不需要考虑如何更改DOM,重点放在修改数据上就可以,数据更新后 使用数据的那个元素会同步更新
                this.food+= "真好吃";
            },
        },
    });
</script>
</html>
4. 计数器案例
  1. 编码步骤
  1. data中定义数据:比如 num 值为1
  2. methods中添加两个方法:比如add(递增) ,sub(递减)
  3. 使用{{}} 将num设置给 span标签
  4. 使用v-on 将add,sub 分别绑定给 + ,- 按钮
  5. 累加到10 停止
  6. 递减到0 停止
  1. 页面准备
<body>
    <div id="app">
        <!-- 计算功能区域 -->
        <div>
            <input type="button" class="btn btn_plus">
            <span>{{num}}</span>
            <input type="button" class="btn btn_minus">
        </div>
    </div>
</body>
<script src="./js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        data:{
            num:1,
        }
    });
</script>
  1. 案例演示
<!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>
    <link rel="stylesheet" href="./css/inputNum.css">
</head>
<body>
    <div id="app">
        <!-- 计算功能区域 -->
        <div>
            <input type="button" class="btn btn_plus" v-on:click="add">
            <span>{{num}}</span>
            <input type="button" class="btn btn_minus" v-on:click="sub">
        </div>
    </div>
</body>
<script src="./js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        data:{
            num:1,
        },
        methods: {
            add:function(){
                if(this.num < 10){
                    this.num++;
                }else{
                    alert("别点了!最大了!");
                }
            },
            sub:function(){
                if(this.num > 0){
                    this.num--;
                }else{
                    alert("别点了!最小了!");
                }
            }
        },
    });
</script>

<script>
    //   案例总结
    //        1.创建Vue实例时:el(挂载点),data(数据),methods(方法)
    //        2.v-on 指令 作用是绑定事件,可以简写为@事件名
    //        3.方法中,使用this关键字获取data中的数据
    //        4.v-text 和 {{}} 都可以获取data中的数据,设置到元素中
</script>
</html>
  1. 案例总结

1、创建VUE实例时: el(挂载点),data(数据),methods(方法)

2、v-on指令的作用是绑定事件,简写为@

3、方法中使用this关键字,获取data中的数据

4、v-text与**{{}}**的作用都是用来设置元素的文本值

5. v-show指令

作用: v-show指令, 根据真假值,切换元素的显示状态

页面准备

<body>
    <div id="app">
        <img src="./img/car.gif">
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app"
    })
</script>

代码示例

<!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>
    <style>
        /*
            v-show: 根据真假值,切换元素的显示状态
        */
    </style>
</head>
<body>
    <div id="app">
        <input type="button" value="切换状态" @click="changeShow">
        <img v-show="isShow" src="./img/car.gif">
        <!-- <img v-show="age > 18" src="./img/car.gif"> -->
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        data:{
            isShow:true,
            age:19
        },
        methods: {
            changeShow:function(){
                // 触发方法,对isShow进行取反
                this.isShow = !this.isShow;
            },
        },
    });
</script>
</html>

v-show 指令总结

1、原理是修改元素的display,实现显示或者隐藏

2、指令后面的内容,最终会解析为布尔值

3、值为true 显示,为false 则隐藏

4、数据改变之后,显示的状态会同步更新

6.v-if 指令

作用:根据表达值的真假,切换元素的显示和隐藏( 操纵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>
    <style>
        /*
            v-if指令: 根据表达式的真假,切换元素的显示和隐藏(操作的是DOM)
                频繁切换就是用 v-show,反之就使用 v-if
                本质上是通过操作DOM元素来切换状态
        */
    </style>
</head>
<body>
    <div id="app">
        <input type="button" value="切换状态" @click="changeShow">
        <img v-if="isShow" src="img/car.gif">
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        data:{
            isShow:false
        },
        methods: {
            changeShow:function(){
                this.isShow = !this.isShow;
            }
        },
    })
</script>
</html>

v-if 指令总结

1、v-if 指令的作用:根据表达式的真假切换元素的显示状态

2、本质是通过操作dom元素,来切换显示状态

3、表达式为true 元素存在与dom树,为false从dom树中移除

4、频繁切换使用 v-show,反之使用v-if

7. v-bind 指令

作用:设置元素的属性(比如:src,title,class)

语法格式:v-bind:属性名=表达式

<imgv-bind:src="imgSrc">
    
varVM=newVue({
    el:"#app",
    data:{
    	imgSrc:"图片地址"
    }
})
    
v-bind可以省略,简写为冒号:
<img :src="imgSrc">

代码示例

<!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>
    <style>
        /*
            v-bind : 设置元素的属性 src class
            语法: v-bind:属性名=表达式

            作用:为元素绑定属性
            完整写法:v-bind:属性名 = 表达式,简写::属性=表达式
        */
    </style>
</head>
<body>
    <div id="app">
        <img src="img/lagou.jpg">

        <!-- 使用 v-bind 设置src属性 -->
        <img v-bind:src="imgSrc">

        <!-- v-bind 可以简写为 : -->
        <img v-bind:src="imgSrc" :title="imgTitle">

        <!-- 设置class -->
        <div :style="{ fontSize: size+'px' }">v-bind指令</div>
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        data:{
            imgSrc:"img/lagou.jpg",
            imgTitle:"拉勾教育",
            size:50
        },
    });
</script>
</html>

v-bind指令总结

? v-bind 指令的作用是:为元素绑定属性

? 完整写法v-bind:属性名=表达式,可以简写为 :属性名=表达式

8. v-for 指令

作用:根据数据生成列表结构

语法结构

<div id="app">
    <ul>
        <li v-for="item in arr"></li>
    </ul>
</div>

var VM = new Vue({
	el:"#app",
	data:{
		arr:[1,2,3,4,5],
		objArr:[
			{name:"tom"},
			{name:"jack"}
		]
	}
});

代码示例

<!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>
    <style>
        /*
            v-for指令:根据数据生成列表结构
            1.数组经常和v-for结合使用
            2.语法格式:(item,index) in 数据
            3.数组的长度变化,会同步更新到页面上,响应式的
        */
    </style>
</head>
<body>
    <div id="app">
        <input type="button" value="添加数据" @click="add">
        <input type="button" value="移除数据" @click="remove">

        <ul>
             <!-- 在li标签中 获取数组的元素 -->
            <li v-for="(item,index) in arr">
                {{index+1}}城市:{{item}}
            </li>
        </ul>

        <!-- 使用h2标签显示 -->
        <h2 v-for="p in persons">
            {{p.name}}
        </h2>
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
       el:"#app",
       data:{
           // 数组
           arr:["上海","北京","广东","深圳"],

           // 对象数组
           persons:[
               {name:"尼古拉斯.赵四"},
               {name:"莱昂纳多.小沈阳"},
               {name:"多利安.刘能"},
           ]
       }, 
       methods: {
               add:function(){
                   // 向数组添加元素 push
                   this.persons.push({name:"小斌"});
               },
               remove:function(){
                   // 移除数据
                   this.persons.shift();
               }
           },
    });
</script>
</html>

v-for指令总结

1、v-for 指令的作用: 根据数据生成列表结构

2、数组经常和 v-for结合使用,数组有两个常用方法:

? push() 向数组末尾添加一个或多个元素

? shift() 把数组中的第一个元素删除

3、语法是: (item,index) in 数据

? item和index 可以结合其他指令一起使用

4、数组的长度变化,会同步更新到页面上,是响应式的

9. v-on 指令补充
  1. 传递自定义参数:函数调用传参
  2. 事件修饰符:对事件触发的方式进行限制

代码示例

<!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>
    <style>
        /*
            1.函数调用传参
                事件绑定方法后,可以传递参数
                定义方法时,需要定义形参,来接收参数
                
            2.事件修饰符
                作用:可以对事件尽心限制,.修饰符
                .enter 可以限制触发的方式为 回车
        */
    </style>
</head>
<body>
    <div id="app">
        <!-- 函数传参 -->
        <input type="button" value="礼物刷起来" @click="showTime(666,'爱你老铁!')">

        <!-- 事件修饰符 指定哪些方式可以触发事件 -->
        <input type="text" @keyup.enter="hi">
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        data:{},
        methods:{
            showTime:function(p1,p2){
                console.log(p1);
                console.log(p2);
            },
            hi:function(){
                alert("你好吗?");
            }
        },
    });
</script>
</html>

总结

1、事件绑定方法,可以传入自定义参数

? 定义方法时,需要定义形参,来接收实际的参数

2、事件的后面跟上 .修饰符可以对事件进行限制

? .enter 可以限制触发的按键为回车

3、事件修饰符有许多使用时可以查询文档

10. 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 http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        /*
            MVVM:前端的架构模式
            M:model 负责存储数据
            V:View   负责页面的展示
            VM:ViewModel 负责业务处理(MVVM模式的核心)
        */
    </style>
</head>
<body>
    <div id="app">
        <!-- View 视图部分 -->
        <h2>{{name}}</h2>
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>

    // 创建的vue实例,就是VM ViewModel
    var VM = new Vue({
        el:"#app",
        // data就是MVVM模式中的 model
        data:{
            name:"hello"
        }
    });
</script>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-enQbVOMp-1627033941601)(E:\MarkDown\拉勾笔记\View Model)]

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

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

? 从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。

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

11. 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 http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        /*
            v-model:实现哈桑想数据绑定
            单项数据绑定:将model绑定到view上,当model发生班花时,view会随之变化
            双向数据绑定:view视图发生变化时,model也会随之改变
        */
    </style>
</head>
<body>
    <div id="app">
        <input type="button" value="修改message" @click="update">
        <!-- View 视图 -->
        <!-- <input type="text" v-bind:value="message"> -->

        <!-- v-model 实现双向绑定 -->
        <input type="text" v-model="message">
        <input type="text" v-model="password">
        <h2>{{message}}</h2>
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    // VM 业务逻辑控制
    var VM = new Vue({
        el:"#app",
        // Model 数据存储
        data:{
            message:"拉勾教育训练营",
            password:123
        },
        methods: {
            update:function(){
                this.message = "拉钩";
            }
        },
    });
</script>
</html>

v-model指令总结

1、v-model 指令的作用是便捷的设置和获取表单元素的值

2、绑定的数据会和表单元素值相关联

3、双向数据绑定

实现简单记事本

1、功能介绍

2、新增内容

? 步骤

  1. 生成列表结构(v-for 数组)
  2. 获取用户输入(v-model 双向绑定)
  3. 回车,新增数据(v-on .enter事件修饰符)
  4. 页面布局不熟悉,可以通过审查元素的方式快速找到元素
<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" 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>
              <button class="destroy"></button>
            </div>
          </li>
        </ul>
      </section>
       <!-- 统计和清空 -->
       <footer class="footer">
        <span class="todo-count"> <strong>1</strong> items left </span>
        <button class="clear-completed">
          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);
              }
          },
      });

  </script>
</html>

3、删除内容

步骤

  1. 点击删除指定的内容( 根据索引删除元素)
  2. 在methods中添加一个删除的方法,使用splice函数进行删除
<!-- 列表区域 -->
<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>
                <!-- 啥删除操作,传递index -->
                <button class="destroy" @click="remove(index)"></button>
            </div>
        </li>
    </ul>
</section>

4、统计操作

步骤

  1. 统计页面信息的个数,就是列表中的元素的个数
  2. 获取 list数组的长度,就是信息的个数
<!-- 统计和清空 -->
<footer class="footer">
    <span class="todo-count"> <strong>{{list.length}}</strong> items left </span>
    <button class="clear-completed" @click="clear()">
        Clear
    </button>
</footer>

总结:

  1. 基于数据的开发方式
  2. v-text设置的是文本,可以使用简化方式 {{}}

5、清空数据

步骤:

  1. 点击清除所有信息
  2. 本质就是清空数组
<buttonclass="clear-completed"@click="clear()">Clear</button>

//清空数组元素
clear:function(){
	this.list=[];
}
<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" href="../vue_test/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>
              <!-- 啥删除操作,传递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>

axios

Ajax回顾

什么是Ajax?

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

Ajax的作用

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

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

异步与同步

浏览器访问服务器的方式

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

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

案例演示

ajax.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <input type="text">
    <input type="button" value="Jquery发送异步请求" οnclick="run1()">
</body>
<script src="jquery-1.8.3.min.js"></script>
<script>
    function run1() {
        // Jquery Ajax方式发送异步请求
        $.aja({
            url:"/ajax",
            async:true,
            data:{
                name:"天青"
            },
            type:"post",
            dataType:"text",
            success:function (res) {
                console.log(res);
                alert("响应成功" + res);
            },
            error:function(){
                alert("响应失败!");
            }
        });
    }
</script>
</html>

servlet

@WebServlet("/ajax")
public class AjaxServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 1.获取请求数据
        String username = req.getParameter("name");

        // 模拟业务操作
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 2.打印username
        System.out.println(username);
        resp.getWriter().write("hello hello");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

axios介绍

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

目前十分流行网络请求库,专门用来发送请求,其内部还是ajax,进行封装之后使用更加方便

axios作用: 在浏览器中可以帮助我们完成 ajax异步请求的发送

Vue2.0之后,尤雨溪推荐大家用axios替换JQuery ajax

axios入门

使用步骤:

1、导包

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

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

GET

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b152Uy9y-1627033941606)(E:\MarkDown\拉勾笔记\axious GET)]

POST

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

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

接口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 http-equiv="X-UA-Compatible" content="IE=edge">
    <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:"张飞"}).then(
           function(resp){
                console.log(resp);
           },
           function(error){
                console.log(error);
           }
       );
   }
</script>
</html>

axios总结

  1. axios 必须导包才能使用
  2. 使用get或者post方法,就可以发送请求
  3. then方法中的回调函数,会在请求成功或者请求失败的时候触发
  4. 通过回调函数的形参可以获取响应的内容,或者错误信息

获取笑话案例

通过vue+axios 完成一个获取笑话的案例

接口: 随机获取一条笑话

请求地址:https://autumnfish.cn/api/joke
请求方法:get
请求参数:无
响应内容:随机笑话

代码示例

<!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>vue+axios获取笑话</title>
    <style>
        /*
            1.axios回调函数中,this指向已经改变,无法访问data中的数据
            2.解决方案:将this进行保存,回调函数中直接使用保存的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>

案例总结

1.axios回调函数中this指向已经改变,无法访问data中的数据

2.解决方案:将this进行保存,回调函数中直接使用保存的this即可

天气查询案例

需求分析

功能分析: 回车查询

? 1.输入内容,点击回车 (v-on.enter)

? 2.访问接口,查询数据 (axios v-model)

? 3.返回数据,渲染数据

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

自定义JS文件

? 作为一个标准应用程序,我们将创建VUE实例的代码,抽取到main.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){

                    }
                );
            }
        },
    })
<!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.服务器返回的数据比较复杂,获取数据的时候 要注意层级结构
      */
    </style>
  </head>

  <body>
    <div class="wrap" id="app">
      <div class="search_form">
        <div class="logo">天气查询</div>
        <div class="form_group">
          <!--绑定点击事件,回车触发,通过v-model绑定数据-->
          <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>
案例总结
  1. 应用的逻辑代码,建议与页面进行分离,使用单独的JS编写
  2. axios中 回调函数中的this 需要先保存 再使用
  3. 服务器返回的数据比较复杂,获取数据时要注意层级结构

解决页面闪烁问题

我们发现访问天气预报案例页面时,使用插值表达式的地方出现了闪烁问题,如何解决呢?

v-cloak指令

? 作用:解决插值表达式闪烁问题

? 当网络较慢,网页还在加载 Vue.js,而导致 Vue 来不及渲染,这时页面就会显示出 Vue 源代码。我们可以使用 v-cloak 指令来解决这一问题。

  1. 添加样式
<style>
    /*通过属性选择器,设置添加了v-cloak*/
    [v-cloak]{
        display:none;
    }
</style>
  1. 在id为app的div中添加 v-cloak
<div class="wrap"id="app" v-cloak>

computed 计算属性

什么是计算属性

在Vue应用中,在模板中双向绑定一些数据或者表达式,但是表达式如果过长,或者逻辑更为复杂时,就会变得臃肿甚至难以维护和阅读,比如下面的代码:

<div>
    写在双括号中的表达式太长了,不利于阅读
    {{text.split(',').reverse().join(',')}}
</div>

将这段操作text.split(',').reverse().join(',')放到计算属性中,最终返回一个结果值就可以

computed的作用:减少运算次数,缓存运算结果。运用于重复相同的计算。

代码示例

<!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>
    <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("res方法执行了!!");
                return this.a + this.b;
            }
        }
    });
</script>
</html>

computed总结

  1. 定义函数也可以实现与计算属性相同的效果,都可以简化运算
  2. 定义函数也可以实现与计算属性相同的效果,但是计算属性可以简化运算
  3. 不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值

filter 过滤器

什么是过滤器

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

? 数据加工车间,对值进行筛选加工。

过滤器使用位置

1、双括号插值内

{{ msg | filterA }} msg是需要处理的数据,filterA是过滤器,| 这个竖线是管道,通过这个管道将数据传输给过滤器进行过滤 加工操作

2、v-bind绑定的值的地方

<h1 v-bind:id=" msg | filterA ">{{msg}}</h1>

过滤器

1、局部过滤器

需求:通过过滤器给电脑价格前面添加一个符号¥

<!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>
</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",  // 挂载点
        data:{ 
            // model
            price:200
        },
        methods: {  // 方法
        },
        computed:{  // 计算属性
        },

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

2、全局过滤器

需求:将用户名开头字母大写

<!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.过滤器经常被用来处理文本格式化操作
          2.过滤器使用的两个位置:{{}} 插值表达式中,v-bind表达式中
          3.过滤器是通过管道传输数据的 |
    */
</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>

总结

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

watch 侦听器

什么是侦听器

Vue.js 提供了一个方法 watch,它用于观察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>
</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 http-equiv="X-UA-Compatible" content="IE=edge">
    <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="firstName"></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:{
            firstName:"",
            lastName:"",
            fullName:""
        },
        // 侦听器
        watch:{
            firstName:function(nval,oval){  // 参数 1.新值,2.旧值
                this.fullName = nval + " "+this.lastName;
            },
            lastName:function(nval,oval){
                this.fullName = this.firstName + " " + nval;
            }
        }
    });
</script>
</html>

Component 组件

组件介绍

? 组件(Component)是自定义封装的功能。在前端开发过程中,经常出现多个网页的功能是重复的,而且很多不同的页面之间,也存在同样的功能。

? 我们将相同的功能进行抽取,封装为组件,这样,前端人员就可以在组件化开发时,只需要书写一次代码,随处引入即可使用。

? 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t6IqwyBg-1627033941619)(E:\MarkDown\拉勾笔记\Component 组件)]

vue的组件有两种: 全局组件 和局部组件

全局组件

语法格式:

Vue.component("组件名称",{
	template:"html代码",	// 组件的HTML结构代码
	data(){	// 组件数据
		return{}
	},
	methods:{	// 组件的相关的js方法
		方法名(){
			// 逻辑代码
		}
	}
})

注意:

  1. 组件名以小写开头,采用短横线分割命名: 例如hello-Word
  2. 组件中的data 必须是一个函数,注意与Vue实例中的data区分
  3. 在template模板中,只能有一个根元素
<!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>
</head>
<body>
    <div id="app">
        <!-- 使用组件 -->
        <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实例里面

newVue({
	el:"#app",
	components:{
		组件名:{
			//组件结构
			template:"HTML代码",
			//data数据
			data(){return{msg:"xxxx"};},
		},
	},
});

注意:

? 创建局部组件,注意 components,注意末尾有 ‘s’,而全局组件是不用+ ‘s’ 的。这意味着,components 里可以创建多个组件。

<!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>
</head>
<body>
    <div id="app">
        <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 http-equiv="X-UA-Compatible" content="IE=edge">
    <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>

总结:

  1. 上面这种写法,浏览器会把 html 里的 template 标签过滤掉。所以 template 标签的内容是不会在页面中展示的。直到它被 JS 中的 Vue 调用。
  2. 在 html 中,template 标签一定要有一个 id,因为通过 id 是最直接被选中的。 data 和 methods等参数,全部都要放到 Vue 实例里面写

Vue生命周期

生命周期图示

每个Vue实例在被创建之前都要经过一系列的初始化过程,这个过程就是vue的生命周期

了解生命周期的好处:

  1. 找错误
  2. 解决需求

下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6a4GzIfY-1627033941624)(E:\MarkDown\拉勾笔记\Vue生命周期)]

钩子函数介绍

生命周期中的钩子函数

钩子函数:钩子函数是在一个事件触发的时候,在系统级捕获到了他,然后做一些操作

函数说明
beforeCreate()在创建Vue实例之前,可以执行这个方法,例如加载动画操作
created()实例创建完成,属性绑定好了,但是DOM还没有生成
beforeMount()模板已经在内存中编辑完成了,尚未被渲染到页面中
mounted()内存中的模板已经渲染到页面,用户已经可以看见内容
beforeUpdate()数据更新的前一刻,组件在发生更新之前,调用的函数
updated()updated执行时,内存中的数据已更新,并且页面已经被渲染
beforeDestory()钩子函数在实例销毁之前调用
destoryed()钩子函数在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>
</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);
        //     this.show();
        // },

        // 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>

Vue Router 路由

什么是路由?

在Web开发中,路由是指根据URL分配到对应的处理程序。路由允许我们通过不同的 URL 访问不同的内容。

通过 Vue.js 可以实现多视图单页面web应用(single page web application,SPA)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZpYTunuX-1627033941627)(E:\MarkDown\拉勾笔记\什么是路由?)]

什么是SPA ?

单页面Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。

单页应用不存在页面跳转,它本身只有一个HTML页面。我们传统意义上的页面跳转在单页应用的概念下转变为了body内某些元素的替换和更新,举个例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PClWN1he-1627033941628)(E:\MarkDown\拉勾笔记\什么是SPA?)]

? 整个body的内容从登录组件变成了欢迎页组件,从视觉上感受页面已经进行了跳转。但实际上,页面只是随着用户操作,实现了局部内容更新,依然还是在index.html 页面中。

单页面应用的好处:

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

路由相关的概念

router :

? 是Vue.js官方的路由管理器。它和Vue.js的核心深度集成,让构建单页面应用(SPA)变得易如反掌,router就相当于一个管理者,它来管理路由。

route:

	ruter相当于路由器,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()为手动挂载,在项目中可用于延时挂载(例如在挂载之前要进行一些其他操作、判断等),之后要手动挂载上。newVue时,el和$mount并没有本质上的不同。
  1. HTM代码
<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>
  1. JS代码
<!-- 导入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>

路由总结

  1. router是Vue中的路由管理器对象,用来管理路由
  2. route是路由对象,一个路由就对应一条访问路径,一组路由用routes表示
  3. 每个路由对象都有两部分 path(路径)和component (组件)
  4. router-link 是对a标签的封装,通过to属性指定连接
  5. router-view 路由访问到指定组件后,进行页面展示

Vue总结

Vue基础

vue简介:

1、前端JavaScript框架

2、特点:渐进式框架,实现即插即用

3、适合前后端分离,国人开发,中文文档

vue.js的使用:

1、引入vue:本地引入、远程引入

2、定义div,指定id

3、创建vue实例:{{}}插值表达式、el:挂载点、data:数据对象

4、渲染数据:vue中的声明式渲染,即我们声明数据,vue帮我们将数据渲染到html

vue指令:

1、v-text指令:获取data数据,设置标签内容

2、v-html指令:设置元素的innerHTML(可以向元素中写入新的标签)

3、v-on指令:Wie元素绑定事件

4、v-show指令:根据真假值,切换元素的显示状态

5、v-if指令:根据表达值的真假,切换元素的显示和隐藏(操纵DOM元素)

6、v-bind指令:设置元素的属性(比如:src,title,class)

7、v-for指令:根据数据生成列表结构

8、v-on补充指令:1)传递自定义参数:函数调用传参;2)事件修饰符:对事件触发的方式进行限制

MVVM模式:

1、model:负责存储数据

2、view:负责页面展示

3、view model:负责业务逻辑处理(比如ajax请求等),对数据进行加工后交给视图展示

v-model指令实现双向数据绑定:

1、单项绑定:把model绑定到view,当我们用JavaScript代码更新model时,view就会自动更新

2、双向绑定:用户更新了view,model的数据也自动被更新了,这种情况就是双向绑定

Vue进阶

axios:

1、作用:axios作用:在浏览器中可以帮助我们完成ajax异步请求的发送

2、先导入后使用

computed 计算属性:

1、作用:减少运算次数,缓存运算结果,应用于重复相同的计算

filter过滤器:

1、作用:过滤器是对即将显示的数据做进一步的筛选处理,然后进行显示

watch侦听器:

1、作用:当你想要监听某一个数据,然后执行一些操作时可以使用侦听器

component组件化开发:

1、组件(component)是自定义封装功能

2、在前端开发过程中,经常出现多个网页的功能是重复的,而且很多不同的页面之间,也存在同样的功能。我们将相同的功能进行抽取,封装为组件,这样,前端人员就可以在组件化开发时,只需要书写一次代码,随处引入即可使用。

vue生命周期:

1、每个Vue实例在被创建之前都要经过一系列的初始化过程,这个过程就是vue的生命周期

2、钩子函数

vue router路由:

1、在Web开发中,路由是指根据URL分配到对应的处理程序

2、单页应用:就是只有一张Web页面的应用,vue中使用路由完成单页面应用的开发

3、使用路由步骤:

  1. 定义路由所需的组件
  2. 定义路由每个路由都由两部分 path (路径) 和component (组件)
  3. 创建router路由器实例,由路由对象routes管理路由
  4. 创建Vue实例,注入路由对象,使用$mount() 指定挂载点

Vue-cli&ElementUI

Vue-cli

什么是Vue-cli

1、Vue cli是基于Vue的应用开发提供的一个标准的脚手架工具。为应用搭建基础的框架结构,提供插件、开发服务、Preset、构建打包功能

2、Vue cli 背后集成了现代化开发的诸多功能,通过简单的命令就可以完成 "零配置"的项目环境搭建

安装Vue-cli步骤

在安装vue-cli前,要确认自己的电脑是否安装了nodejs和npm。

安装Node.js

安装了node.js才能使用npm ,才能安装vue-cli

什么是node.js

1、node.js是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型。

2、JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。

安装node.js
  1. 下载对应你系统的Node.js版本:https://nodejs.org/en/download/

我们统一安装: node-v12.18.1-x64.msi

  1. 选安装目录进行安装

  2. 测试:在命令提示符下输入命令

node -v	// 会显示当前node的版本
安装NPM

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

自动安装NPM

node.js已经集成了npm工具

在命令提示符输入 npm -v 可查看当前npm版本

npm -v
查看包管理路径

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

npm config ls

我们发现NPM默认的管理包路径在:

C:\Users\Administrator\npm
设置包管理路径

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

  1. 我们选择一个路径,专门存放这些依赖包。我选择创建一个目录:D:\MySoftware\nodejs_package
  2. 在D:\MySoftware\nodejs_package下再创建npm_modules文件夹和npm_cache文件夹:
npm config set prefix "D:\MySoftware\nodejs_package\npm_modules"

npm config set cache "D:\MySoftware\nodejs_package\npm_cache"
  1. 此时再使用npm config ls查询NPM管理包路径发现路径已更改
NPM环境变量配置
  1. 查看npm的全局路径是什么
npm config get prefix
  1. 配置PATH环境变量

添加新的系统变量: key=NODE_HOME , value= D:\MySoftware\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

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

注意:以管理员身份打开命令行

  1. 安装命令
npm install -g @vue/cli
  1. 输入 vue命令
vue
  1. 输入 vue -V 查看版本
vue -V

快速构建Vue项目

步骤说明

1、创建一个空的文件夹vuecli_work

2、以管理员身份运行cmd,进入到vuecli_work文件夹

3、执行下面的命令

1.基于交互式命令方式,创建项目
//文件名不支持驼峰(含大写字母)使用短横线方式

vue create my-project

4、选择自定义安装,点击回车

5、 在这列表中,选择我们要安装的组件,使用空格键选择,选好后回车

6、按回车之后,提示选择什么模式的路由,我们输入 n (表示选择hash模式)

7、选择项目配置文件单独存放

8、是否保存模板,选择n不创建

9、安装完成,提示输入执行下面这两个命令

10、首先进入项目目录:cd my-project

11、启动项目:npm run serve

12、访问项目: http://localhost:8080/

13、停止项目只要关闭命令行窗口就可以

导入Vue项目到VSCode

1、VSCode中右键选择打开文件夹

2、选择创建的项目

3、打开项目,可以看到如下项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LXb4rbaP-1627033941632)(E:\MarkDown\拉勾笔记\VueCLi项目目录结构)]

项目结构介绍
|---my-project 项目名称
    |---node_modules 存放依赖包的目录
    |---public 静态资源管理目录
    |---src 组件源码目录(我们写的代码)
        |---assets 存放静态图片资源(CSS也可以放在这里)
        |---components 存放各种组件(一个页面可以看做一个组件),各个组件联系在一起组成一个完整的项目
        |---router 存放了项目路由文件
        |---views 放置的为公共组件(主要还是各个主要页面)
        |---App.vue 可以当做是网站首页,是一个vue项目的主组件,项目页面入口文件
        |---main.js 打包运行的入口文件,引入了vue模块和app.vue组件以及路由route
    |---babel.config.jsbabel 配置文件,对源代码进行转码(把es6=>es5)
    |---package.json 项目及工具的依赖配置文件
    |---paxkage-lock.json 依赖配置文件
    |---README.md 项目说明
Vue脚手架自定义配置
package.js 介绍

? 每个项目的根目录下面,一般都有一个package.json文件,定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。npm install命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。

{
	
	// 1.项目基本信息
	"name": "my-project",
	"version": "0.1.0",
	"private": true,

	// 2.指定的运行脚本的命令
	"scripts": {
		"serve": "vue-cli-service serve",
		"build": "vue-cli-service build"
	},
	
	// 3.生产环境所依赖的 模块版本
	"dependencies": {
		"core-js": "^3.6.5",
		"vue": "^3.0.0",
		"vue-router": "^4.0.0-0"
	},
	
	// 4.本地开发环境使用的依赖版本
	"devDependencies": {
		"@vue/cli-plugin-babel": "~4.5.0",
		"@vue/cli-plugin-router": "~4.5.0",
		"@vue/cli-service": "~4.5.0",
		"@vue/compiler-sfc": "^3.0.0"
	}
	
	// 自定义配置
	
}
npm install 
通过package.json 配置项目

配置内容采用JSON格式所有的内容都用双引号包裹

1、打开package.json,再最末端添加如下配置:

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

2、配置说明:该配置设置打包时服务器相关的信息

? port : 访问端口

? open true: 打包完成自动打开浏览器

3、启动项目

1)在VSCode中选择项目,右键在终端打开

2) 输入命令:npm run serve

3)运行后发现端口号改为 8888,并且在打包完成后自动打开浏览器

? 注意: 不推荐这种方式,因为package.json主要是用来管理包的配置信息。为了方便维护,我们将Vue脚手架相关的配置单独定义到vue.config.js配置文件中

单独的配置文件配置项目

1、在项目的根目录创建文件vue.config.js

2、删除掉package中新添加的配置项

3、在vue.config.js 文件中进行相关配置

module.exports = {
	devServer:{
		open:true,
		port:8088
	}
}
Vue 组件化开发
组件化开发

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

组件介绍
  1. 我们用 vue-cli 脚手架搭建的项目,里面有很多,如index.vue或者App.vue这一类的文件。

每一个***.vue 文件都是一个组件,是一个自定义的文件类型**,比如App.vue就是整个项目的根组件。

  1. 常见的组件:

? 页面级别的组件

? 页面级别的组件,通常是views目录下的.vue组件,是组成整个项目的各个主要页面

? 业务上可复用的基础组件

? 这一类组件通常是在业务中被各个页面复用的组件,这一类组件通常都写到components目录下,然后通过import在各个页面中使用

  1. 组件的组成部分

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>

项目运行流程

main.js

1、项目运行会加载入口文件main.js

// 在vue中使用 import 变量名 from 文件路径
import { createApp } 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的区域
App.vue

2、App.vue 是vue项目的主组件,是页面入口文件,所有页面都是在App.vue下进行切换的

App.vue 中的模板(HTML代码)
<template>
  <div id="app">	挂载的区域
      
    <div id="nav">
        // 是路由的导航链接
        // 1.to="/" 是项目的根路径,是跳转的首页
      <router-link to="/">Home</router-link> |
        
        // 2.to="/about" 单击跳转到 about组件
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>

<style></style>
router 路由

3、找到路由文件,来看一下具体的路由配置

// 引入所需文件
import Vue from 'vue'
import VueRouter from 'vue-router'

// 引入了 Home.vue
import Home from '../views/Home.vue'

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

// 创建路由集合,元素就是一个一个路由规则
const routes = [
  {
    path: '/',		// 路径
    name: 'Home',	// 路由名称
    component: Home // Home = Home.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: () => // 指向了 About.vue组件
      import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

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

// export 用来表示导出模块
export default router
Home.vue组件

4、默认访问的是Home.vue首页

// 视图部分
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
      
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

// JS部分
<script>
// @ is an alias to /src
// @符号表示 src这个目录
import HelloWorld from '@/components/HelloWorld.vue'

// 导出
export default {
  name: 'Home',
  components: {
    HelloWorld
  }
}
</script>

组件的使用案例

创建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: #eee;
    text-align: center;
    color: blue;
}
</style>
引入 Header组件

修改Home.vue

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
    <Header/>
  </div>
</template>

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

export default {
  name: 'Home',
  components: {
    // HelloWorld
    Header
  }
}
</script>
组件的传参

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

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

<script>
// JS部分
export default {
    name:"Header",  // 组件的名称
    // 参数传递
    props:['msg']
}
</script>

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

Element-UI

Element-UI介绍

element-ui是饿了么前端出品的基于Vue.js的后台组件库,方便程序员进行页面快速布局和构建

Element-UI官方站点:https://element.eleme.cn/#/zh-CN

Element-UI使用

命令行方式安装

1、创建一个新的项目

2、当前项目下打开终端,安装依赖包,执行下面的命令

npm i element-ui -S

3、打开 main.js,导入Element-UI 相关资源

main.js是工程的入口文件,在此文件中加载了很多第三方组件,如:Element-UI、Base64、VueRouter等

// 导入elementUI组件库
import ElementUI from 'element-ui'

// 导入组件相关样式
import 'element-ui/lib/theme-chalk/index.css'

// 配置EL到vue上
Vue.use(ElementUI)

4、复制Element按钮样式到app.vue文件的template下

<template>
  <div id="app">
    <div id="nav">
      <el-row>
        <el-button disabled>默认按钮</el-button>
        <el-button type="primary" disabled>主要按钮</el-button>
        <el-button type="success" disabled>成功按钮</el-button>
        <el-button type="info" disabled>信息按钮</el-button>
        <el-button type="warning" disabled>警告按钮</el-button>
        <el-button type="danger" disabled>危险按钮</el-button>
      </el-row>

      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>

5、启动项目 npm run serve,查看页面

Vue-CLI工程改造

1、删除components目录下的HelloWord.vue组件

2、删除App.vue中的部分内容,只保留如下部分

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

<style>
</style>

3、删除router文件下的路由文件index.js部分内容,只保留如下部分

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

Vue.use(VueRouter)

const routes = []

const router = new VueRouter({
  routes
})

export default router

4、删除views目录下的About.vue与Home.vue

安装axios

1、npm安装:使用npm下载axios包

npm i axios

2、在main.js文件中导入axios相关资源

//引入axios
import axios from 'axios'

//Vue对象使用axios
Vue.prototype.axios = axios;

用户登录界面制作

Dialog对话框组件

我们可以用Dialog制作一个登陆弹窗,选择自定义内容

<el-dialog title="收货地址" :visible.sync="dialogFormVisible">
  <el-form :model="form">
    <el-form-item label="活动名称" :label-width="formLabelWidth">
      <el-input v-model="form.name" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="活动区域" :label-width="formLabelWidth">
      <el-select v-model="form.region" placeholder="请选择活动区域">
        <el-option label="区域一" value="shanghai"></el-option>
        <el-option label="区域二" value="beijing"></el-option>
      </el-select>
    </el-form-item>
  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button @click="dialogFormVisible = false">取 消</el-button>
    <el-button type="primary" @click="dialogFormVisible = false">确 定</el-button>
  </div>
</el-dialog>
创建login.vue 组件

1、在components下创建Login.vue

2、将Diglog组件的内容,拷贝到Login.vue,进行修改:

<template>
    <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 {
            dialogFormVisible: true,
            formLabelWidth: '120px'
        }
    },
}
</script>

<style scoped>

</style>
配置路由
import Vue from 'vue'
import VueRouter from 'vue-router'

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

Vue.use(VueRouter)

const routes = [
  // 登录路由
  {
    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>

<style>
    
</style>
编写登录功能

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

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

2、修改登陆触发事件

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

3、双向数据绑定

? data中定义数据

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>

4、编写login方法

methods: {
        // 登录的方法
        login(){

            // 定义常量保存url
            const url = "";

            // 发送请求
            this.axios(url,{
                // 携带的参数
                param:{
                    username:this.user.username,
                    password:this.user.password
                }
            }).then(function(resp){
                console.log(resp);
                alert("登录成功");
            }).catch(
                // function (error) {}
                error => {}
            );
        }
    },
Postman搭建mock server

? Mock server就是模拟一个服务器,我们使用Mock server可以模拟后台接口,对请求进行响应。

? 在前后端分离的开发中前端利用mockeserver模拟出对应接口,拿到返回数据来调试,无需等后端开发人员完成工作。

postman模拟出一个server 步骤:

1、使用postman模拟出一个server

2、打开如下窗体,创建一个伪服务

1)第一步

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FuxC9kQG-1627033941633)(E:\MarkDown\拉勾笔记\Postman搭建mock server01)]

2)第二步

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3pshQtZ-1627033941635)(E:\MarkDown\拉勾笔记\Postman搭建mock server02)]

3)第三步

4)第四步 修改请求的URL

const url = "复制上面的地址/login";
登录成功后跳转

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

methods: {
        // 登录的方法
        login(){

            // 定义常量保存url
            const url = "https://8fdd2435-45d6-4f80-9677-cdf1b03d5608.mock.pstmn.io/login";

            // var that = this;

            // 发送请求
            this.axios(url,{
                // 携带的参数
                param:{
                    username:this.user.username,
                    password:this.user.password
                }
            }).then((resp) => {
                console.log(resp);
                alert("登录成功");
                // 成功 关闭对话框
                this.dialogFormVisible = false;

                // 进行页面跳转,跳转到首页,在前端进行页面跳转 必须使用路由
                this.$router.push('index');
            }).catch(
                // function (error) {}
                error => {
                    // 登录失败 提供消息提示
                    this.$message.error('对不起!登录失败!');
                }
            );
        }
    },

首页布局页面制作

创建index.vue
<template>
    <el-button type="danger">布局页面</el-button>    
</template>

<script>
export default {}
</script>

<style scoped>

</style>
配置路由

router目录下的index.js路由文件

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

const routes = [
    // 布局路由
    {
        path:"/index",
        name:"index",
        component:Index
    }
];
布局容器

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

1、在官方文档中找到布局的容器代码,复制到Index.vue

<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>

<style scoped>
.el-container{
    height: 570px;
}
.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>

2、拷贝布局容器中的导航菜单代码,进行修改,代码如下

<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>Main</el-main>
            </el-container>
        </el-container>
    </div>
</template>

<script>
export default {}
</script>

<style scoped>
.el-container{
    height: 570px;
}
.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
<template>
    <el-button type="danger">课程信息</el-button>    
</template>

<script>
export default {}
</script>

<style scoped>

</style>
配置路由

1、在index.js路由文件中,为布局路由添加children属性表示子路由

// 导入课程组件
import Course from "@/components/Course";

 // 布局路由
  {
    path:"/index",
    name:"index",
    component:Index,

  // 添加子路由,使用children属性 来表示子路由
  children:[
    // 课程信息子路由
    {
      path:"/course",
      name:"course",
      component:Course
    }
  ]
  },

2、修改Index.vue组件中的导航菜单属性

router表示是否使用vue-router的模式,启用该模式会在激活导航时以index作为path进行路由跳转

el-menu中添加一个router属性
<el-menu
	default-active="2"
    class="el-menu-vertical-demo"
    backgroundcolor="#D3DCE6"
    router
>

3、为index属性指定路由

<el-menu-item-group>
	<el-menu-item index="/course"><i class="el-icon-menu"></i>课程管理</el-menu-item>
</el-menu-item-group>

4、设置路由的出口,将课程信息展示再main

<!-- 主要区域 -->
<el-main>
    <router-view></router-view>
</el-main>

Table表格组件

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

添加表格组件

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

<template>
    <el-table :data="tableData" stripe style="width: 100%">
        <el-table-column prop="date" label="日期" width="180"></el-table-column>
        <el-table-column prop="name" label="姓名" width="180"></el-table-column>
        <el-table-column prop="address" label="地址"></el-table-column>
    </el-table>
</template>

<script>
export default {
    data() {
        return {
            tableData: [
            {
                date: '2016-05-02',
                name: '王小虎',
                address: '上海市普陀区金沙江路 1518 弄'
            }]
        };
    }
}
</script>
表格组件说明

我们查看一下,ElementUI的表格的代码,分析一下表格数据是如何显示的

//视图部分 进行页面展示
<template>
    //el-table组件 绑定了tableData数据
    <el-table :data="tableData" style="width: 100%">
        //el-table-column 表示表格的每列,prop属性与模型数据中的key对应 ,label 列名
        <el-table-column prop="date" label="日期" width="180"></el-table-column>
        <el-table-column prop="name" label="姓名" width="180"></el-table-column>
        <el-table-column prop="address" label="地址"></el-table-column>
    </el-table>
</template>

<script>
//export default 相当于提供一个接口给外界,让其他文件通过 import 来引入使用。
export default {
    //data() 函数
    data() {
		return {
            //数据部分
            tableData: [
                {
                    date: "2016-05-02",
                    name: "王小虎",
                    address: "上海市普陀区金沙江路 1518 弄"
            	}
            ]
    	};
	}
};
</script>

课程内容展示

修改Course.vue

1、编写template,复制ElementUI的示例代码,进行改动

<template>
    <el-table v-loading="loading" element-loading-text="拼命加载中" :data="courseList" stripe style="width: 100%">
        <el-table-column prop="id" label="ID"></el-table-column>
        <el-table-column prop="course_name" label="课程名称"></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>

2、编写VM部分代码

<script>
export default {
    data() {
        return {
            loading:true,
            courseList: []
        };
    },
    // 钩子函数created,在DOM页面生成之前执行
    created() {
        // 在页面生成之前,调用 loadCourse()
        this.loadCourse();
    },
    methods: {
        // 方法1:获取课程信息
        loadCourse(){
            alert("loadCourse方法执行了");
            // 发送请求获取课程数据
            const url = "http://localhost:8080/lagou_edu_home/course";
            return this.axios.get(url,{
                params:{
                    methodName:"findCourseList"
                }
            }).then((res) => {
                console.log(res.data);
                // 将获取到的数据 赋值给
                this.courseList = res.data;

                // 取消加载动画
                this.loading=false;
            }).catch((error) => {
                this.$message.error("获取数据失败!");
            });
        }
    },
}
</script>
跨域问题解决
出现跨域问题

当我们在前端项目中,向后端发送请求的获取课程数据的时候,出现了跨域问题:

? 已被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向一个不同的域请求数据,只要协议、域名、端口有任何一个不同,都被当作是不同的域,浏览器就不允许跨域请求。

? 跨域的几种常见情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-arwPqKU8-1627033941636)(E:\MarkDown\拉勾笔记\跨域的几种情况)]

解决跨域问题

? 跨域的允许主要由服务器端控制。服务器端通过在响应的 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>

2、在web.xml中配置跨域filter

<!--配置跨域过滤器-->
<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>
再次查询

解决跨域问题之后,页面显示数据

条件查询

ElementUI输入框组件

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m67D0VG7-1627033941638)(E:\MarkDown\拉勾笔记\Input输入框)]

Course.vue添加输入框

<div>
    <!-- 条件查询 -->
    <el-input placeholder="请输入课程名称"><i slot="prefix" class="el-input__icon el-icon-search"></i>
    </el-input>
    
    <!-- 表单显示 ... -->
</div>
Layout 布局

通过基础的 24 分栏,迅速简便地创建布局。

通过 row 和 col 组件,并通过 col 组件的span属性我们就可以自由地组合布局。

1、Row 组件提供gutter属性来指定每一栏之间的间隔,默认间隔为0。

<el-row :gutter="20">
    <el-col :span="6"><div class="grid-content bg-purple"></div></el-col>
</el-row>

2、使用分隔,分隔查询条件

<el-row :gutter="20">
    <el-col :span="6">
        <el-input  prefix-icon="el-icon-search" placeholder="课程名称" v-model="input" clearable></el-input>
    </el-col>
</el-row>

3、添加一个按钮

<el-row :gutter="20">
    <el-col :span="6">
        <el-input  prefix-icon="el-icon-search" placeholder="课程名称" v-model="input" clearable></el-input>
    </el-col>
    <el-col span="1">
        <el-button type="primary">点击查询</el-button>
    </el-col>
</el-row>
完成根据课程名查询

1、双向数据绑定

Model 模型

data() {
    return {
        loading:true,
        courseList: [],
        filter:{course_name:""}
    };
},

View 视图

<el-input prefix-icon="el-icon-search" placeholder="课程名称" v-model="filter.course_name" clearable></el-input>

2、设置点击事件

<el-button type="primary" @click="search">点击查询</el-button>

3、methods中添加方法

// 根据课程名查询
search(){
    // 开启加载提示
    this.loading=true;

    // 发送请求
    const url = "http://localhost:8080/lagou_edu_home/course";
    return this.axios.get(url,{
        // 携带参数
        params:{
            methodName:"findByCourseNameAndStatus",
            course_name:this.filter.course_name
        }
    }).then((res) => {
        console.log(res.data);
        this.courseList = res.data;

        // 关闭加载
        this.loading=false;
    }).catch((error) => {
        this.$message.error("获取数据失败");
    })
},

小结

VUE-CLI脚手架

什么是vue-cli

1、基于vue的应用开发提供的一个标准的脚手架工具

2、通过简单的命令就可以完成“零配置”的项目环境搭建

安装vue-cli

1、安装node.js:JavaScript运行环境

2、安npm:

? 1)包管理和分发的工具

? 2)设置包管理路径:放在c盘不太合适;创建目录,专门存放这些依赖包

? 3)配置path环境变量

? 4)安装cnpm

3、安装3.x版本的vue-cli:

? npm install -g @vue/cli

cli构建项目

1、创建一个空文件夹

2、以管理员身份运行cmd,进入到文件夹

3、执行命令:

? 1)vue create my-project

? 2)文件名不支持驼峰命名(含大写字母)使用短横线方式

4、按步骤完成配置

5、将项目导入 VS Code

cli项目结构介绍

vue脚手架自定义配置

1、package.js:定义了这个项目所需要的各种模块,以及项目的配置信息等数据

2、vue.config.js:将vue脚手架相关的配置单独定义到vue.config.js配置文件中

vue组件化开发

1、介绍

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

2、组件分类

? 1)页面级别的组件

? 2)业务上可复用的基础组件

3、组件的组成部分

? 1)template:组件的HTML部分

? 2)script:组件的js脚本(使用es6语法编写)

? 3)style:组件的css样式

项目运行流程

1、main.js:项目运行会加载入口文件 main.js

2、app.vue:vue项目的主组件,是页面的入口,所有页面都是在app.vue下进行切换的

3、router路由:进行页面的跳转

4、home.vue组件:

? 1)首页

? 2)内引入了helloworld.vue组件

ELEMENT-UI

element-ui介绍

1、element-ui是饿了么前端出品的基于vue.js的后台组件库

element-ui安装

1、创建项目,在终端打开

2、执行命令:npm i element-ui -S

3、main.js中引入:

? 1)导入组件库:import elementui from ‘element-ui’

? 2)导入组件相关样式:import ‘element-ui/lib/theme-chalk/index.css’

? 3)配置vue插件,将el安装到vue上:vue.use(elementui);

vue-cli工程改造

1、删除项目构建时生成的一些页面

安装axios

1、执行命令:npm i axios

2、main.js引入

element-ui案例

1、用户登录页面制作:

? 1)dialog对话框组件

? 2)创建login.vue组件

? 3)配置路由

? 4)完成登录功能

? 5)postman搭建mock server

? 6)登录跳转

2、首页布局页面制作

? 1)创建index.vue

? 2)配置路由

? 3)布局容器container

3、导航菜单的路由设置

? 1)编写course.vue

? 2)配置路由

4、table表格组件

? 1)通过table组件来实现一个课程页面展示的功能,通过查看element-ui库,我们需要table表格

5、课程内容展示

? 1)请求后台,获取课程数据

? 2)跨域问题:指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,只要协议、域名、端口有任何一个不同,都被当做是不同的域,浏览器就不允许跨域请求

? 3)解决跨域问题:后台解决,设置response响应头数据即可;引入了解决跨域的依赖

6、条件查询

? 1)elementui输入框组件

? 2)layout布局

? 3)完成根据课程名查询

前后端项目接口联调

联调准备

运行后台项目

1、clean清空项目的编译文件

2、compile重新编译项目

3、将项目部署到 tomcat

? 项目名为: lagou_edu_home

? 端口号: 8080

4、部署图片上传路径为 webapps目录下的 upload目录

运行前端项目

1、首先导入前端项目到 VSCode

2、运行项目

课程管理首页

获取课程列表

JS部分

<script>
//引入axios
import { axios } from "../utils";

export default {
  name: "Courses",
  title: "课程管理",
  //定义数据部分
  data() {
    return {
      filter: { course_name: "", status: "" }, //查询对象
      courses: [], //课程信息集合
      loading: false //是否弹出加载
    };
  },

  //钩子函数
  created() {
    this.loadCourses();
  },

  methods: {
    //方法1: 获取课程列表
    loadCourses() {
      this.loading=true;

      // 请求后台查询课程列表接口
      return axios.get("/course",{
        params:{
          methodName: "findCourseList"
        }
      }).then(resp => {

        console.log(resp);
        this.courses = resp.data;
        this.loading=false;
      }).catch((error) => {
        this.$message.error("数据获取失败!!!");
      })
    },
      
  }
};
</script>

条件查询课程信息

JS部分

//方法2: 条件查询课程信息
filterQuery() {

    this.loading = true;

    // 请求后台条件查询接口
    return axios.get("/course",{
        // 准备参数
        params:{
            methodName:"findByCourseNameAndStatus",
            course_name:this.filter.course_name,
            status:this.filter.status
        }
    }).then(resp => {
        this.loading = false;
        this.courses = resp.data;
    }).catch((error) => {
        this.$message.error("数据获取失败!!!");
    })
},

跳转到添加课程

JS部分

//方法3: 添加课程跳转方法
addCourse() {
    // 路由跳转到CourseItem.vue
    this.$router.push({
        name:"CourseItem",params:{courseID:"new"}
    });
},

修改课程状态

JS部分

//方法4: 修改课程状态
updateStatus(item) {
    // item表示选中的数据 = Course对象
    axios.get("/course",{
        params:{
            methodName:"updateCourseStatus",
            id:item.id
        }
    }).then(resp => {

        // 将返回的状态字段数据,封装到item对象中
        Object.assign(item,resp.data);

        // 重新加载页面
        window.location.reload;
    }).catch(error => {
        this.$message.error("修改课程状态失败!!!");
    })
},

跳转课程营销或内容管理

JS部分

//方法5: 根据路由名称, 导航到对应组件
handleNavigate(name, id) {
    // 根据参数 使用对应的路由 导航到指定的组件
    this.$router.push({name,params:{courseId:id}});
},

新建&修改课程

Course组件中的跳转方法

<!-- 营销信息按钮 -->
<el-button size="mini" @click="handleNavigate('CourseItem', scope.row.id)">营销信息</el-button>
//方法3: 添加课程跳转方法
addCourse() {
    // 路由跳转到CourseItem.vue
    this.$router.push({
        name:"CourseItem",params:{courseId:"new"}
    });
},

router.js 路由

找到name为: CourseItem的路由

//添加课程的路由
{
    path: "/courses/:courseId", //路径,携带参数: 课程ID
    name: "CourseItem",
    component: () =>
    //路由导航到的组件
    import(/* webpackChunkName: 'courses' */ "../views/CourseItem.vue")
},

CourseItem组件

JS部分
	//数据部分
    return {
      rules, //规则
      course: {}, //课程
      loading: false,
      params: {}
    };
  },
  //钩子函数
  created() {
    //1.显示当前页面在网站中的位置
    this.$breadcrumbs = [
      { name: "Courses", text: "课程管理" },
      { text: "营销信息" }
    ];

    // 1.获取路由传递的参数
    const id = this.$route.params.courseId;

    // 2.判断id是否有值,没有值就跳转到 错误页面
    if(!id) return this.redirectToError();

    // 3.有id中值,判断是new,还是具体的课程id
    if(id === "new"){
      // new 代表是新增操作
      this.course.title = "新增课程";
    }else{
      // 否则就是修改操作
      // alert("修改操作ID = "+id);
      // 根据id查询课程信息,进行回显
      this.loadCourse(id);
    }
  },
图片上传分析

页面部分

<!-- 上传图片部分 -->
<el-form-item label="分享小图" prop="share_image_title">
    <el-input v-model="course.share_image_title" type="text">
        <!-- :auto-upload="false",取消自动上传,:on-change="onchange" 调用onchange进行处理 -->
        <el-upload 
                   slot="prepend" 
                   :auto-upload="false" 
                   :on-change="onchange" 
                   action 
                   :limit="1">
            <el-button size="small" type="primary">点击上传</el-button>
        </el-upload>
    </el-input>
</el-form-item>

JS部分

FormData的主要用途有两个

1、将form表单元素的name与value进行组合,实现表单数据的序列化,从而减少表单元素的拼接,提高工作效率。

2、异步上传文件

3、创建FormData对象

data中创建FormData
// 4.在钩子函数中创建FormDate对象,将图片与表单其他内容 一通上传
this.params = new FormData();

methods添加方法
//文件上传
onchange(file) {
    if(file != null){
        // 将文件信息,保存到 FormDate对象中
        // 参数1:表示文件上传项 参数2:文件上传的二进制数据 参数3:文件名
        this.params.append("file",file.raw,file.name);
    }
},
新建课程信息

JS 部分

//方法1: 保存和修改课程信息
handleSave() {

    // 1.校验表单是否正确
    this.$refs.form.validate(valid => {
        // 判断校验是否通过
        if(!valid) return false;

        // 1.设置Content-Type类型为:多部件上传
        let config = {
            headers:{
                "Content-type":"multipart/form-data"
            }
        }

        // 2.获取到表单数据,保存到params中(params就是FormDate对象)
        for(let key in this.course){
            // debugger
            console.log(key + " = " + this.course[key]);
            this.params.append(key,this.course[key]);
        }

        // 3.请求后台接口 保存课程信息
        axios.post("/courseSalesInfo",this.params,config).then(resp => {
            if(resp.data.status == 0){
                // 保存成功,跳转回首页
                this.$router.back();
            }else if(resp.data.status == 1){
                // 保存失败
                this.$message.error(resp.data.msg);
            }
        }).catch(error => {
            this.$message.error("保存课程信息失败!!!");
        });

    })

},
修改课程信息
//方法2: 根据ID 回显课程信
loadCourse(id) {

    this.loading = true;

    axios.get("/course",{
        params:{
            methodName:"findCourseById",
            id:id
        }
    }).then(resp => {
        this.loading = false;
        this.course = resp.data;
    }).catch(error => {
        this.$message.error("回显数据失败!!");
    });
},

内容管理

Course组件中的跳转方法

<!-- 内容管理按钮 -->
<el-button size="mini" @click="handleNavigate('CourseTasks', scope.row.id)">内容管理</el-button>
//方法5: 根据路由名称, 导航到对应组件
handleNavigate(name, id) {
    // 根据参数 使用对应的路由 导航到指定的组件
    this.$router.push({name,params:{courseId:id}});
},

router.js 路由

//内容管理的路由
{
    path: "/courses/:courseId/tasks",
    name: "CourseTasks",
    meta: { requireAuth: true },
    component: () =>
    import(/* webpackChunkName: 'courses' */ "../views/CourseTasks.vue")
}

CourseTasks组件

树形控件测试

1、 打开我们之前编写的VueCLI项目

2、在component目录下,添加一个组件,TestTree.vue

<template>

</template>

<script>
    export default {
        
    }
</script>

<style scoped>
</style>

3、在Index.vue组件中的导航菜单位置添加一个 树形控件导航

注意:要设置index的路径为 /tree

<el-submenu index="1">
    <template slot="title">
        <i class="el-icon-location"></i>
        <span>导航菜单</span>
    </template>
    <el-menu-item-group>
        <el-menu-item index="/course"><i class="el-icon-menu"></i>课程管理</el-menu-item>

        <el-menu-item index="/tree"><i class="el-icon-menu"></i>树形控件</el-menu-item>
    </el-menu-item-group>                           
</el-submenu>

4、 在index.js 路由文件中进行配置,在布局路由中再添加一个子路由

import Tree from "@/components/TestTree"

// 布局路由
  {
    path:"/index",
    name:"index",
    component:Index,

  // 添加子路由,使用children属性 来表示子路由
  children:[
    // 课程信息子路由
    {
      path:"/course",
      name:"course",
      component:Course
    },
    {
      path:"/tree",
      name:"tree",
      component:Tree
    }
  ]
  },

5、在ElementUI官网中查找树形控件

6、先来查看基础用法,复制代码到 TestTree.vue

<template>    
     <el-tree :data="data" :props="defaultProps"></el-tree>
</template>

<script>
export default {
    data() {
      return {
        data: [{
          label: '一级 1',
          children: [{
            label: '二级 1-1',
            children: [{
              label: '三级 1-1-1'
            }]
          }]
        }, {
          label: '一级 2',
          children: [{
            label: '二级 2-1',
            children: [{
              label: '三级 2-1-1'
            }]
          }, {
            label: '二级 2-2',
            children: [{
              label: '三级 2-2-1'
            }]
          }]
        }, {
          label: '一级 3',
          children: [{
            label: '二级 3-1',
            children: [{
              label: '三级 3-1-1'
            }]
          }, {
            label: '二级 3-2',
            children: [{
              label: '三级 3-2-1'
            }]
          }]
        }],
        defaultProps: {
          children: 'children',
          label: 'label'
        }
      };
    },
    methods: {
      handleNodeClick(data) {
        console.log(data);
      }
    }
}
</script>

<style scoped>

</style>

7、 Tree组件属性分析

**data:**展示数据

**props:**配置树形结构

? label : 设置节点名称

? children: 指定生成子树的属性名称

8、自定义树节点内容:

data:数据对象

node:节点对象

<el-tree :data="data" :props="defaultProps">
    <!-- slot-scope:作用域插槽
			node:当前节点对象
			data:当前数据对象
	-->
    <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{data.label}}</span>
        <span>级别:{{node.level}}</span>
    </span>
</el-tree>

9、 展示树形结构章节与课时

<template>
    <!-- 
        data:展示的数据
        props:配置树形结构
            defaultProps: {
            children: 'children',   // 指定生成子树的属性名称
            label: 'label'          // 节点名称
            }
     -->
     <el-tree :data="data" :props="defaultProps">
         <!-- slot-scope:作用域插槽
                node:当前节点对象
                data:当前数据对象
          -->
         <span class="custom-tree-node" slot-scope="{ node, data }">
             <span>{{data.section_name || data.theme}}</span>
        </span>
     </el-tree>
</template>

<script>
export default {
    data() {
      return {
        data: [
            {
            id: 5,
            course_id: 10,
            section_name: "麻式太极",
            description: "麻式太极拳,你动我试试",
            orderNum: 0,
            status: 2,
            create_time: "2019-07-11 10:55:10.0",
            update_time: "2019-10-09 12:43:01.0",
            isDel: 0,
            lessonList: [
                {
                id: 32,
                course_id: 10,
                section_id: 5,
                theme: "第一讲:如何给自己洗脑",
                duration: 10,
                is_free: 1,
                order_num: 1,
                status: 2,
                create_time: "2019-01-23 20:37:02.0",
                update_time: "2020-02-24 18:37:34.0",
                isDel: 0
            },
            {
                id: 33,
                course_id: 10,
                section_id: 5,
                theme: "第二讲:如何给别人洗脑",
                duration: 10,
                is_free: 1,
                order_num: 1,
                status: 2,
                create_time: "2019-01-23 20:37:02.0",
                update_time: "2020-02-24 18:37:34.0",
                isDel: 0
            }],

        }],

        // 树形结构的展示
        defaultProps: {
          children: 'lessonList',
          label: item => {
              return item.section_name || item.theme
          }
        }
      };
    },
    methods: {
      handleNodeClick(data) {
        console.log(data);
      }
    }
}
</script>

<style scoped>

</style>
显示当前课程的名称

1、显示当前课程名称

<!-- 显示当前课程的名称 -->
<el-page-header @back="() => this.$router.back()" :content="addSectionForm.course_name" />

2、data数据

data() {
    //定义章节信息
    const addSectionForm = {
      course_id: undefined,
      course_name: "",
      section_name: "",
      description: "",
      order_num: 0
    };

    //章节与课时信息,树形结构
    const treeProps = {
      label: item => {
        return item.section_name || item.theme;
      },
      children: "lessonList"
    };

    //定义章节状态信息
    const statusMapping = {
      0: "已隐藏",
      1: "待更新",
      2: "已更新"
    };

    const statusForm = {
      status: 0
    };

    return {
      addSectionForm,
      treeProps,
      sections: [],
      statusForm, //状态表单
      statusMapping,

      loading: false, //树形控件
      showAddSection: false, //添加或修改章节
      showStatusForm: false //状态修改
    };
  },

3、 加载课程信息

created() {
    //1.显示当前页面在网站中的位置
    this.$breadcrumbs = [
      { name: "Courses", text: "课程管理" },
      { text: "课程结构" }
    ];

    //2. 从路由中获取传递的参数, 课程id
    const id = this.$route.params.courseId;
    if (!id) return this.redirectToError();

    //3.加载课程信息
    this.loadCourse(id);

    //4.加载课程对应的章节与课时
    this.loadChildren(id);
  },
  methods: {
    //方法1: 加载课程信息
    loadCourse(id) {
      axios.get("/courseContent",{
        params:{
          methodName:"findCourseById",
          course_id:id
        }
      }).then(resp => {
        // 将数据保存到 表单对象中
        this.addSectionForm.course_id = resp.data.id,
        this.addSectionForm.course_name = resp.data.course_name;
      }).catch(error => {
        this.$message.error("数据获取失败!!!");
      })
    },
  }
加载章节与课时信息

JS部分

//方法2: 加载树(章节与课程)
    loadChildren(id) {

      this.loading = true;

      axios.get("/courseContent",{
        params:{
          methodName:"findSectionAndLessonByCourseId",
          course_id:id
        }
      }).then(resp => {
        // 获取数据 保存到 sections
        this.sections = resp.data;
        this.loading = false;
      }).catch(error => {
        this.loading = false;
        this.$message.error("数据获取失败!!!");
      })

    },

HTML

? el-tree ElementUI树形控件

? :data 列表数据

? :props 配置选项

 <el-tree
      :data="sections"
      :props="treeProps"
      v-loading="loading"
      element-loading-text="数据加载中..."
    >
      <!-- slot-scope:代表当前树节点内容,有两个参数 data表示当前树节点, node表示当前节点状态 -->
      <div class="inner" slot-scope="{ data, node }">
        <span>{{ data.section_name || data.theme }}</span>

? :props 配置选项

? **label:**指定节点标签为节点对象的某个属性值

? **children:**指定子树为节点对象的某个属性值

//章节与课时信息,树形结构
    const treeProps = {
      label: item => {
        return item.section_name || item.theme;
      },
      children: "lessonList"	// 返回的JSON数据中的lessonList集合
    };

? 操作按钮显示

? node.level 获取当前节点的级别

? @click.stop 事件冒泡,点击哪个元素,就执行哪个元素绑定的事件

<!-- 操作按钮 -->
<span class="actions">
    <!-- 编辑章节  @click.stop 阻止事件冒泡 -->
    <el-button v-if="node.level == 1" size="small" @click.stop="handleEditSection(data)">编辑</el-button>

    <!-- 修改章节状态 -->
    <el-button v-if="node.level == 1" size="small" @click.stop="showStatus(data)"
               >{{ statusMapping[data.status] }}</el-button>
</span>
回显信息

HTML

<!-- 添加章节按钮 -->
<el-button type="primary" icon="el-icon-plus" @click="handleShowAddSection">添加章节</el-button>

JS部分

//方法3: 显示添加章节表单,回显课程信息
handleShowAddSection() {
    this.showAddSection = true;
},
添加章节

HTML

<el-button type="primary" @click="handleAddSection">确 定</el-button>

JS

//方法4: 添加&修改章节操作
    handleAddSection() {
      axios.post("/courseContent",{
        methodName:"saveOrUpdateSection",
        section:this.addSectionForm
      }).then(resp => {
        debugger;
        this.showAddSection = false;
        // 重新加载页面
        return this.loadChildren(this.addSectionForm.course_id);
      }).then(() =>{
        // reset 重置表单
        this.addSectionForm.section_name = '';
        this.addSectionForm.description = '';
        this.addSectionForm.order_num = 0;
      }).catch(error => {
        this.$message.error("操作执行失败!!!");
      })
    },
后台接口问题解决

BaseServlet中代码修改

if("application/json;charset=utf-8".equals(contentType))

修改为:
if("application/json;charset=utf-8".equalsIgnoreCase(contentType))

CourseContentServlet中的saveOrUpdateSection方法修改

//3.使用BeanUtils的 copyProperties方法,将map中的数据封装到section对象里

//BeanUtils.populate(section,map);
BeanUtils.copyProperties(section,map.get("section"));
修改章节

HTML

<!-- 编辑章节  @click.stop 阻止事件冒泡 -->
<el-button v-if="node.level == 1" size="small" @click.stop="handleEditSection(data)">编辑</el-button>

JS回显示方法

//方法5: 修改章节回显方法
handleEditSection(section) {
    // 对象拷贝
    Object.assign(this.addSectionForm,section);
    this.showAddSection = true;
},

事件冒泡:当点击子元素的事件。如果父元素也有同样的事件的话。他就会一并的触发。

解决冒泡事件的方法: @click.stop

<body>
    <!-- 事件冒泡 : 当点击子元素的事件。如果父元素也有同样的事件,那么也会触发
         解决方式:@click.stop
    -->
    <div id="app" @click="log('div点击事件!!')">
        <button @click.stop="log('button的点击事件!!!')">按钮</button>
    </div>
</body>
<script src="js/vue.min.js"></script>
<script>
    var VM = new Vue({
        el:"#app",
        methods:{
            log(t){
                alert(t);
            }
        }
    })
</script>
章节状态回显

HTML

<!-- 修改章节状态 -->
<el-button v-if="node.level == 1" size="small" @click.stop="showStatus(data)">{{ statusMapping[data.status] }}</el-button>

JS

//定义章节状态信息
const statusMapping = {
    0: "已隐藏",
    1: "待更新",
    2: "已更新"
};
//方法6: 显示章节状态
showStatus(data) {
    console.log(data);
    // 保存状态表单数据
    this.statusForm.id = data.id;
    this.statusForm.status = data.status.toString();
    this.statusForm.data = data;
    // 显示表单对话框
    this.showStatusForm = true;
},
Select选择器

1、打开我们之前编写的VueCLI项目

2、在component目录下,添加一个组件,TestSelect.vue

<template>
    
</template>

<script>
export default {}
</script>

<style scoped>

</style>

3、 在Index.vue组件中的导航菜单位置添加一个 Select选择器 导航

注意:要设置index的路径为 /select

<el-menu-item index="/select"><i class="el-icon-menu"></i>select选择器</el-menu-item>

4、在index.js 路由文件中进行配置,在布局路由中再添加一个子路由

import Select from "@/components/TestSelect"

{
     path:"/select",
     name:"select",
     component:Select
},

5、在ElementUI官网中查找Select选择器

6、查看基础用法,将代码复制到 TestSelect.vue中

<template>
    <!-- v-model的值为当前选项的value属性值 label 选项的标签名-->
    <el-select v-model="value" placeholder="请选择">
        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
    </el-select>
</template>

<script>
export default {
    
    data() {
      return {
        options: [{
          value: '选项1',
          label: '黄金糕'
        }, {
          value: '选项2',
          label: '双皮奶'
        }, {
          value: '选项3',
          label: '蚵仔煎'
        }, {
          value: '选项4',
          label: '龙须面'
        }, {
          value: '选项5',
          label: '北京烤鸭'
        }],
        value: ''
      }
    }
}
</script>

<style scoped>

</style>

7、select 选择器属性分析

**v-model:**的值为当前被选中的el-option的 value 属性值

**el-option:**选项

? label 选项的标签名

? value 选择的值

8、使用Select选择器展示状态信息

<template>
    <!-- v-model的值为当前选项的value属性值 label 选项的标签名-->
    <el-select v-model="status" placeholder="请选择">
        <el-option v-for="item in Object.keys(statusMapping)" :key="item" :label="statusMapping[item]" :value="item"></el-option>
    </el-select>
</template>

<script>
export default {
    
    data() {
      return {
        statusMapping:{
            0: "已隐藏",
            1: "待更新",
            2: "已更新"
        },
        status:"",
      };
    }
};
</script>

Object.keys()

var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']
章节状态修改

HTML

<el-button type="primary" @click="handleAddSection">确 定</el-button>

JS部分

//方法7: 修改章节状态
    updateStatus(statusForm) {
      axios.get("/courseContent",{
        params:{
          methodName:"updateSectionStatus",
          id:this.statusForm.id,
          status:this.statusForm.status
        }
      }).then(resp => {
        this.statusForm.data.status = this.statusForm.status;
        this.statusForm = {};
        this.showStatusForm = false;
      }).catch(error => {
        this.showStatusForm = false;
        this.$message.error("修改状态失败!!!");
      });
    },

v-for里面数据层次太多, 修改过数据变了,页面没有重新渲染,需手动强制刷新。

@change="$forceUpdate()" 强制刷新

项目上线部署发布

前言

服务器与操作系统

1、服务器是计算机的一种,它比普通计算机运行更快、负载更高、价格更贵。

2、服务器从硬件上等同于电脑PC。而服务器跟PC都是由CPU、内存、主板、硬盘、电源等组成;但服务器的性能要远远超过PC,因为它要保证全年无休。

3、操作系统:操作系统是作为应用程序与计算机硬件之间的一个接口

? 1)没有安装操作系统的计算机,被称为裸机, 如果想在裸机上运行自己的程序,就需要使用机器语言

? 2)安装操作系统之后,就可以配置一些高级语言的环境,进行高级语言的开发

4、Linux操作系统

? 1)Linux系统是最具稳定性的系统

? 2)Linux是天生就比Windows更具安全性

? 3)免费,Linux服务器在应用开发上更能节约成本

项目的发布部署

项目的开发流程大致要经过一下几个步骤:

1、项目立项

2、需求分析阶段

3、原型图设计阶段

4、开发阶段

5、测试阶段

6、系统上线

后台项目部署

安装虚拟机

在Linux阶段我们已经安装过了虚拟机,使用的是 Linux操作系统 CentOS 7 版本

安装软件环境

以下软件,在Linux阶段都已安装完成。具体操作详见该阶段安装文档。

软件版本
JDK11
Tomcat8.5
MySQL5.7

1、查看Java版本

java -version

2、查看tomcat是否能够正常启动

# 进入到tomcat目录
cd /usr/tomcat/

# 启动tomcat
./bin/startup.sh

# 关闭tomcat
./bin/shutdown.sh 

3、关闭防火墙

#查看已经开放的端口:
firewall-cmd --list-ports

#开启端口
firewall-cmd --zone=public --add-port=8080/tcp --permanent

#命令含义:   
	–zone #作用域
	–add-port=8080/tcp #添加端口,格式为:端口/通讯协议   
	–permanent #永久生效,没有此参数重启后失效

#重启防火墙
firewall-cmd --reload               #重启firewall

#关闭防火墙
systemctl stop firewalld.service    #停止firewall
systemctl disable firewalld.service #禁止firewall开机启动
firewall-cmd --state  #查看默认防火墙状态(关闭后显示notrunning,开启后显示running)

4、登录MySQL,检查数库连接是否正常

-- 创建用户
CREATE USER 'Weiwei'@'%' IDENTIFIED BY 'Weiwei@666';

-- 授予所有权限
GRANT ALL PRIVILEGES ON *.* TO 'Weiwei'@'%' IDENTIFIED BY 'Weiwei@666';

-- 刷新
FLUSH PRIVILEGES;

5、使用SQLYog连接Linux上的MySQL,导入SQL脚本 创建项目所需的数据库

项目打包 发布

1、修改项目的数据库配置文件,数据库的IP,用户名 密码都要修改。

2、修改 Constants常量类中的项目URL

//生产环境地址
public static final String LOCAL_URL = "http://192.168.44.128:8080";

3、修改后启动项目,测试一下 保证数据库连接没有问题

4、检查POM文件,打包方式必须是war,编译版本为JDK11

<packaging>war</packaging>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

5、执行打包命令

//清除target文件夹
clean

//打包 ,跳过测试
package

6、复制出target目录下的 war包

7、修改一下项目名称

8、上传到tomcat中,启动测试

//访问接口
http://192.168.44.128:8080/lagou_edu_home/course?methodName=findCourseList

前端项目部署

修改配置文件

1、前端项目的配置文件有两个,一个是开发环境的配置文件,一个是生产环境的配置文件。

.env.development	// 开发环境
.env.production		// 生产环境

2、我们先修改一下开发环境文件的 后端服务器访问地址,然后进行一下测试

.env.development 文件
VUE_APP_API_BASE = http://192.168.44.128:8080/lagou_edu_home

3、修改生产环境的配置文件

//.env.production
VUE_APP_API_BASE = http://192.168.44.128:8080/lagou_edu_home

前端项目打包

1、修改 vue.config.js 配置文件

复制下面内容即可

module.exports = {
    // relative path for dev
    publicPath: process.env.NODE_ENV === "production" ? "/edu-boss/" : "./",
    // for gh-pages
    indexPath: "index.html",
    assetsDir: "static",
    lintOnSave: process.env.NODE_ENV !== "production",
    productionSourceMap: false,
    css: {
        // sourceMap: process.env.NODE_ENV !== 'production'
    },
    devServer: {
        open: true,
        port: 8081
    }
};

2、执行下面的打包命令

npm run build

3、 在项目下会生成一个 dist 目录

4、在本地tomcat的webapps目录下,创建一个edu-boss文件夹,将dist目录中的文件拷贝到里面

5、启动本地tomcat,访问前端项目 路径为:

http://localhost:8081/edu-boss/

前端项目发布

1、验证没有问题后,将edu-boos项目压缩,上传到tomcat服务器

//复制一份tomcat
cp -r /usr/tomcat/ /usr/tomcat2

//上传 edu-boss.zip ,并解压
unzip edu-boss.zip

//删除edu-boss.zip
rm -rf edu-boss.zip

2、修改tomcat2的server.xml 配置文件,修改3个端口,避免与tomcat1冲突

3、在部署后端项目的tomcat1的 webapps目录下创建一个 upload文件夹,保存图片

4、运行前端项目

//进入tomcat2,启动项目
./bin/startup.sh 

//动态查看日志
tail -f logs/catalina.out 

5、运行后端项目

//进入tomcat1,启动项目
./bin/startup.sh

//动态查看日志
tail -f logs/catalina.out 

6、 前后端都启动后,进行测试

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 23:56:02  更:2021-07-24 23:56:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 19:27:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码