从原生JavaScript到Vue前端工程化开发和部署

**醉后不知天在水,满船清梦压星河。


1 JavaScript

1.1 JavaScript的介绍

JavaScript、HTML和CSS是Web开发中三种不同但密切相关的技术。

HTML(超文本标记语言):HTML是一种创建网页结构和内容的标记语言,负责描述网页的结构。它定义了网页中的文本、图像、链接等元素,以结构化的方式来组织和呈现这些元素。

CSS(层叠样式表):CSS是定义网页外观和样式的样式表语言,负责定义网页的外观和样式。通过选择器和属性来选择和修改HTML元素,并为元素添加样式,如颜色、字体、布局等。

JavaScript:JavaScript是一种用于为网页添加交互性和动态功能的解释型脚本语言。它可以与HTML和CSS进行交互、操作DOM(文档对象模型)、发送网络请求等。改变网页的内容、样式和行为,来响应用户的操作和事件,实现丰富的用户体验和动态交互。

html完成了网页的结构和内容,再通过css美化,但这时候的网页是死的,没有交互性,我们还需要利用JavaScript与HTML和CSS集成,并通过操作DOM来改变网页的结构和样式。此外,JavaScript还可以处理各种操作,如表单验证、数据处理、动画效果、图像操作以及与服务器的通信(通过AJAX等技术)。

1.2 JavaScript的引入和基本用法

JavaScript的代码有两种引入方式:

第一种方式: 内部脚本,将JS代码定义在HTML页面中

JavaScript代码必须位于标签内

在HTML文档中,可以在任意地方,放置任意数量的

<script>
    alert("Hello JavaScript!"); 
</script>

第二种方式: 外部脚本,将JS代码定义在外部JS文件中,然后引入到 HTML页面中

外部JS文件中,只包含JS代码,不包含script标签,引入外部js的script标签,必须是双标签。且注意,JavaScript.js文件中不用加script标签

image-20230727124753143.png

外部引入:

<script src="../js/JavaScript.js"></script>

注释:

单行注释:// 注释内容

多行注释:/* 注释内容 */

JavaScript的三种输出方式:

API 描述
window.alert() 警告框
document.write() 在HTML输出内容
console.log() 写入浏览器控制台

如弹出警告框:

image-20230727112738538.png

1.4 JavaScript对象

Array:JavaScript中的Array对象用于定义数组,相当于Java中的集合,数组长度可变,而JavaScript是弱类型,所以可以存储任意类型的数据。

定义创建方式:

var arr = new Array(1, 2, 3, 4);

var arr = [1, 2, 3, 4];
访问:arr[0] = “Hello”;

属性:arr.length,可以设置或者返回数组中元素的个数

方法:

arr.forEach( (e) => {console.log(e)} ),遍历数组中每个有值的元素,调用一次传入的函数。

arr.push(5, 6, 7),添加元素到数组末尾。

arr.splice(2, 2),删除从2开始的两个元素

String:String字符串对象创建的两种方式

var str = new String("Hello JS!")
var str = "Hello JS!"
属性:str.length,返回字符串长度





方法:
str.charAt(3),返回指定位置的字符
str.indeof("llo"),检索该字符起始位置
str.trim(),去除字符串两边空格
str.substring(),截取从a开始到b的字符串,不包括b

JavaScript自定义对象

var user = 
    { name:"Bree",




      age:21,




      gender:"male",

      run: function(){ alert("跑步") }

调用:user.name,user.run()

JSON对象:Javascript Object Notation,JavaScript对象标记语言,通过JavaScript对象标记法书写的文本。语法简单,结构简明,多用于作为数据载体,在网络中进行数据传输。

定义:var jsonStr = ‘{ “key01”: “Bree”, “key02”: 21, “arr01”: [“男”, “女”] }’

JSON字符串转化为JS对象:var jsObj = JSON.parse(jsonStr);

JS对象转化为JSON字符串:var jsonStr = JSON.stringify(jsObj);

BOM对象:Browser Object Model,浏览器对象模型,JavaScript将浏览器的各个组成部分封装成对象,允许JavaScript与浏览器对话。

组成: Window:浏览器窗口对象

Location:地址栏对象(重点前两,从这以下都是window对象的属性)

Navigator:浏览器对象

Screen:屏幕对象

History:历史记录对象

Window对象方法:

window.alert(“消息”),或直接alert(“消息”),显带有消息和确认按钮的警告框

window.comfirm(“消息”),显示带有一段消息与确认和取消的对话框,点击确认返回true,取消返回false

window.setInterval( 某函数(), 2000 ),参数为某函数和时间(毫秒),周期性调用函数

window.setTimeout( 某函数(), 2000 ),参数为某函数和时间(毫秒),在指定时间后调用函数

window的属性和方法的调用都可以省略window对象

window.location.href:设置或返回完整的url

DOM对象:Document Object Model,文档对象模型(如xml),将标记语言的各个标签元素封装为对应的对象。HTML中的element对象可以通过document对象获取,而document对象是通过window对象获取的,window对象可以省略。

文档中的对象:

document:整个文档对象

element:标签元素对象

attribute:属性对象

text:标签元素当中的文本对象

comment:注释对象

获取document对象中的element对象的方法:

1、根据id获取:var ele01 = document.getElementById(‘id01’);

2、根据标签名获取:var divs = document.getElementsByTagName(‘div’);

3、根据name属性值获取:var brees = document.getElementsBy(‘bree’);

4、根据class属性值获取:var classes = document.getElementsByClassName(‘cls’);

修改对象属性:

var div01 = divs\[0] //获取到第一个元素对象 
div01.innerHTML = "明天是比赛日!" //设置文本内容




var img = document.getElementById('img01');
img.src = "../images/bree.jpg"; //设置图像url

1.5 JavaScript事件监听

事件:HTML事件是发生在HTML元素上的”事情”。 如:

按钮被点击
鼠标移动到元素模块上 
按下键盘按键

事件监听:监听到这些事件时会执行相应的JS代码。

事件绑定:

1、通过HTML标签中的事件属性:

<input type="button" onclick="click()" value="按钮01">
<script>

 function click(){
     alert("点击事件发生,执行此方法");

 }

</script>

2、通过DOM元素对象绑定:

<input type="button" id="btn01" value="按钮02">
<script>

document.getElementById("btn01").onclick=function(){
     alert("点击事件发生,执行此方法");

 }

</script>

常见事件绑定:

> onclick:鼠标单击事件,鼠标点击元素模块 
onblur:元素失去焦点事件,鼠标离开元素模块点击
onfocus:元素获取焦点,鼠标移动到元素模块点击
onload:页面或图像完全加载 
onsubmit:表单提交时触发事件 
onkeydown:按下某个键 
onmouseover:鼠标被移到某元素模块上 
onmouseout:鼠标从某元素模块移开

2 通过链接使用vue.js

前后端不分离的项目中,客户端向服务器发送请求获取页面,服务端接收到请求后生成数据并挂载到HTML页面中一并返回。

前后端分离项目中降低了这种数据与页面的耦合,后端只需要关注数据处理,前端只需要关注数据的渲染和挂载。客户端向服务器发送请求获取页面,服务器中的前端此时可以响应页面了,但缺少数据,所有又向服务端发送请求,然后服务端响应数据给前端,然后通过前端美化后响应给用户。

Vue是一套基于MVVM模型的渐进式前端js框架,免除原生JavaScript中的DOM操作,简化书写。基于MVVM(Model-View-View-Mode)思想,其实就是得益于前后端分离项目中需要前后端数据的一致性。所以Vue的MVVM模型脱胎于MVC前后端不分离的设计模式,在MVC中控制器这块比较拥堵繁琐,而MVVM提供了数据绑定和一个可组合的组件系统,实现数据的双向绑定,将编程的关注点放在数据上。简单地说,这种js框架可以单独开发出动态的的页面应用,然后通过MVVM实现页面与服务端进行双向的数据连接和绑定。

MVVM实现双向数据绑定的核心是VM,也就是ViewModel,ViewModel负责连接View和Model,保证视图和数据模型的一致性。ViewModel负责向服务端发送请求获取后端的数据,然后绑定到vue对象的组件页面上,最终被挂载渲染到HTML网页上。

屏幕截图 2023-08-02 172622.png

2.1 基本用法

2.1.1 常用指令

v-bind:为html标签绑定在数据模型中声明的属性值如href、css样式等,v-bind:href="url" 或者 :href="" 
v-model:在元素上创建双向数据绑定 v-on:标签上绑定事件,单击事件:v-on:click("handle")或者用@click("handle"),还有@blur:离焦事件,@focus:聚焦事件 
v-if、v-else-if、v-else:条件性渲染某元素标签,判定为true时渲染,否则不创建该标签元素 
v-show:根据条件展示某标签元素,区别在于切换css样式的display属性的值 
v-for:列表渲染,用于遍历容器或数组中的元素和对象的属性

引入Vue.js,创建vue实例对象,然后在html页面中声明一个将被Vue所控制的Dom区域,即MVVM中的View。

<head>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="app">
        <input type="text" v-model="message">{{message}} <!-- 数据双向绑定,在网页输入则绑定到data中 -->
        <hr><a v-bind:href="link">百度</a><hr>
        <p v-if="flag">flag: 开</p>   <!-- 条件flag=false,标签不被创建,不显示 -->
        <p v-show="!flag">!flag: 关</p> <!-- flag=false,标签被创建,通过css隐藏不显示,性能好 -->
        <button @click="offon">开关</button>
    </div>
</body>
​
<script>
    Vue.createApp({ // Vue2: new Vue
        data: function(){ //在data中指定页面数据源,即Model,如可以返回一个json对象
            return {
                    message: 'Hello Vue!',
                    link:"http://www.baidu.com/",
                    flag: true,
                   }
        },
        methods: {
            offon(){
                this.flag = !this.flag; //为vue对象中data的相应属性赋值
            }
        }
    }).mount('#app') //将数据传给实例对象,绑定到当前vue对象控制的页面区域
</script>

2.1.2 列表渲染

<div id="app">


    <ul>
        <!-- 可以重复生成标签 -->
        <li v-for="(user, i) in userList" :key="user.id" > 索引是:{{i}},姓名是:{{user.name}}</li> 
        <!-- 为li标签加key属性,为每一个被循环的标签加一个唯一的索引,后面组件化开发时不加会报错 -->
    </ul>
</div>
Vue.createApp({
    data: function(){
        return { 
                userList: [
                    {id: 1, name: "bree1"},
                    {id: 2, name: "bree2"},
                    {id: 3, name: "bree3"},
                ]
               }//指定数据源,即Model,如可以返回一个json对象
    }
}).mount('#app')//将数据传给实例对象,绑定当前vue实例对象控制页面的区域

2.1.3 事件绑定

<div id="app">


    {{ message }}
    <a v-bind:href="link">bree</a>
    <botton v-on:click="addCount">+1</botton>{{count}}    <!--或者 <botton @click="addCount">+1</botton> -->
</div>

Vue.createApp({

	data: function(){

		return { 

             	message: 'Hello Vue!',

             	link: "http://www.bree.com/",

            	count: 0,

               }//指定数据源,即Model,如可以返回一个json对象

	},

    methods: {

        addCount(){

            this.count += 1 // 对vue对象中data的相应属性进行加和
        },


    },

}).mount('#app')//将数据传给实例对象,绑定当前vue实例对象控制页面的区域

2.2 生命周期

生命周期是指一个vue对象从创建到销毁的整个过程。分为八个阶段,每触发一次生命周期事件,就会自动执行一个生命周期方法(钩子)。

我们主要掌握两个阶段,一个叫做created函数,当组件组件被创建该函数会被调用;另一个叫做mounted函数,当app挂载完成,页面完全渲染后调用。这两个函数与data和methods平级:

<div id="app">


	{{ message }}
    <a v-bind:href="link">bree</a>
    <botton v-on:click="addCount">+1</botton>    <!--或者 <botton @click="addCount">+1</botton> -->
</div>

Vue.createApp({

	data: function(){

		return { 

             	message: 'Hello Vue!',

             	link: "http://www.bree.com/",

            	count: 0,

               }//指定数据源,即Model,如可以返回一个json对象

	},

    methods: {

        addCount(){

            this.count += 1
        },


    },

    created: funcation(){//每个组件都有自己的生命周期函数,组件每次被创建时都会调用一次。
    	console.log("组件被创建了!")//作用就是可以在里面发送axios请求
	},
    mounted (){//表明vue初始化成功,html页面渲染成功,在该方法当中发送请求到服务端,获取数据。
        alert("vue对象挂载完成,发送请求到服务器!")
    },
}).mount('#app')//将数据传给实例对象,绑定当前vue实例对象控制页面的区域

3 前后端分离开发

混合开发:

首先,在前后端混合开发模式当中,开发人员要开发一个项目,既需要使用前端的技术栈来开发前端的功能,有需要使用Java技术栈来编写功能实现,还需要操作数据库,这样的开发模式将前端代码和后端代码全都写在一个工程当中了,前后端代码耦合度高,那么开发过程中对前端开发人员与后端开发人员的对接上要求很高,沟通成本高,分工不明确,项目不便于管理和维护扩展。

分离开发:

当前最为主流的开发模式是前后端分离开发:前端工程和后端工程。前端工程要通过发送异步请求消息,后端工程进行处理后再返回响应消息,实现前后端的数据交互。

这样前端工程与后端工程就由独立的团队进行开发,所以在开发过程中要实现对接功能必须遵守开发规范,开发规范根据产品经理提供的页面原型与功能需求,定义在专门的文档当中,称为接口文档。接口文档中定义了各个接口功能,描述功能的基本信息,请求参数,响应数据。

有了接口文档后前后端开发工程师就可以根据接口文档的描述进行开发: 需求分析->接口定义(API接口文档)->前后端并行开发(遵守规范)->前后端测试->前后端联调测试

接口文档有在线接口文档与离线接口文档。离线接口文档一般如md文件等,常用的在线接口文档的管理平台有YAPI、Swagger和Rap等等。

3.1 YAPI

YApi是高效、易用、功能强大的api管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。

主要两大服务:API接口管理、Mock数据模拟服务

地址:yapi.pro/

打开网站注册登录:

添加项目:项目对应的接口文档。

添加分离:将项目接口划分为几个模块。

添加接口:编辑具体的基本设置、请求参数设置、返回数据测试,以及设置Mock。

4 前端工程化VueCli

编码工具:VS Code 依赖管理:NPM 项目构建:VueCli

NPM(Node Package Manager):是一个NodeJS包管理和分发工具,最常见就是用于安装和更新依赖。要使用NPM,首先要安装包含NPM工具的NodeJS(前端工程化的运行环境),是一个基于Chrome V8引擎的JavaScript运行时环境。NodeJS是VueCli工具的依赖环境。

VueCli:是Vue官方提供的构建项目的模板工具,通常成为脚手架,用于快速搭建一个带有热重载(自动呈现修改后的效果),以及构建生产版本等功能的单页面应用。

VueCli基于webpack构建,也可以通过项目内的配置文件进行配置 下载安装脚手架:npm install -g @vue/cli

VueCli提供了如下功能:

统一的目录结构 
本地调试 
热部署 
单元测试 
集成打包上线

4.1 安装步骤

首先在官网上下载好NodeJS并安装在指定磁盘文件中,然后在打开命令行窗口,输入node -v验证NodeJS的是否安装成功。第二再进行npm的全局安装路径,输入cmd以管理员身份打开命令行窗口,输入npm config set prefix “NodeJS的安装路径”,然后回车配置好npm全局安装路径。最后切换npm的淘宝镜像,以便后期加速资源的下载,以管理员的身份运行命令行窗口,执行npm config set register registry.npm.taobao.org,切换资源下载镜像。

NodeJS安装完后就可以安装VueCli脚手架了,以管理员的身份运行命令行窗口,执行npm install -g @vue/cli,zid联网下载,等待一段时间后vue的脚手架安装成功。之后在命令行中执行vue –version验证是否安装成功。

安装完后就可以在文件目录下通过命令行快速生成一个Vue的项目模板了

vue create hello:创建一个叫”hello”的前端项目

eslint是检查语法风格的,现在用不着

image-20230728145530686.png

如图向下选择该选项按空格取消选择,也就是前面说的eslint

image-20230728145649409.png

选择最新版本vue3,继续回车

image-20230728145925669-1690973850331.png

选择相关配置和依赖记录的方式,这里选json文件就行,类似于maven项目中的xml文件。如给项目安装Element-ui时可以加[-S]将依赖信息记录到package.json中,下载的很多依赖包都是放在node_modules文件夹,文件内容很多,不方便导出。所以当导出项目时可以把node_modules文件删除,当要项目运行时,在该项目下打开终端,输入npm install,安装程序会自动扫描当前项目下的package.json文件,通过package.json中的依赖信息下载相关的依赖包。

image-20230728150134061.png

是否为项目保存快照,方便以后基于快照快速创建项目,最后等待连网下载项目即可。

image-20230728150304551.png

如图整个项目以及下载完成,通过脚手架创建的项目工程目录结构如下:

image-20230728155050948.png

源码目录下:(链接和组件对应关系的设置可以单独创建router文件夹存放路由的js文件)

image-20230728155716865.png

4.2 组件化开发

4.2.1 开发流程

组件(Component)是Vue.js最强大的功能之一。组件可以扩展HTML元素,封装可重用的代码。Vue的组件系统允许我们使用小型、独立和通常可复用的组件构建大型应用。

Vue中规定组件的后缀名是 .vue,其中App.vue是vue提供的根组件

每个 .vue 组件都由3部分构成,分别是: 
template:组件的模板结构,包含HTML标签及其他的组件,这是在页面中显示的结构 
script:组件的JavaScript代码,控制组件模板数据来源和行为 
style:组件的样式

项目开发流程:首先在components目录下创建一个组件如Movie.vue

image-20230728213336524.png

编写组件的视图、数据模型和样式,其中template中只能有一个根标签,一般用div包含

<template>









    <div>





        <h1>书名:{{ title }}</h1>
        <span>作者:{{ author }}</span>
        <br>
        <button @click="fun">点击加入书架</button>
    </div>
</template>

<script>
    export default{ //这里可以导出组件的数据,便于外面的组件可以导入
        props:["title", "author"], //这里可以自定义组件的属性名称,外部使用组件实现不同展示时可以设置新的属性值
        data: function(){

        },
        methods: {
            fun(){
                alert("添加成功!")
            }
        },
    }
</script>

<style></style>

因为App.vue已经在入口文件main.js中进行导入然后创建Vue对象并挂载渲染到相应的标签上,所以直接在App.vue中的script标签下导入和注册Hello.vue组件:

import Hello from './components/Book.vue'

export defaut{
    name: App,
        components: {
            Book
        }
}

导入Book组件后,可以在App.vue的视图上定义,使用组件的属性进行外部传值,然后与App.vue一起渲染到页面上:

<Book v-for="book in books" :key="book.id" :title="book.title" :author="book.author"></Book>

4.2.2 兄弟组件的数据共享

同一父组件下的兄弟组件的数据共享,可以通过。。。

4.3 Element-UI

Element是国内饿了么公司提供的一套开源前端框架,简洁优雅,提供了Vue、React、Angular等多个版本。

安装:npm i element-ui [-S] 文档地址:element.eleme.cn/#/zh-CN/

在main.js中引入Element:

导入element-ui:

import ElementUI from 'element-ui';

导入element-ui内部组件用到的样式文件:

import 'element-ui/lib/theme-chalk/index.css';

最后在main.js中进行全局注册,这样element-ui中的所有组件都注册了,可以在任意组件下使用:

Vue.use(ElementUI);

然后就可以通过官方文档进行组件开发了。打开官方文档,在组件下有很多组件实例可以使用,如:

image-20230729103014066.png

我们可以在组件实例下复制代码进行使用,在template中使用element-ui的组件,element-ui提供的组件都是以”el-“开头的,组件中定义有很多属性,外部组件可以根据不同的数据展示进行赋值。如图:

image-20230729104834983.png

显示:

image-20230729105220611.png

4.4 图标库

除了组件外,有时候网站还需要一些图标,ElementUI提供的图标较少,一般用到其他的图标库。这样对于网站来说就不需要引入图片作图片,直接通过图标库的标签就可以显示出来了。

第三方图标库 如 Font Awesome:

文档地址:fontawesome.dashgame.com/ 安装:npm install font-awesome 使用:import ‘font-awesome/css/font-awesome.min.css’

需要在哪用就放在哪,如:

<i class="fa fa-camera-retro"></i>

5 前端异步通信技术

在实际项目开发中,前端页面所需要的数据往往需要从服务器端获取,这必然涉及与服务器的通信。

首先先来了解Ajax请求:

概念:Asynchronous JavaScript And XML,异步的JavaScript和XML。Ajax是一种前端技术,用于实现异步通信和 动态更新网页内容。 作用: 通过异步交互进行数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据。简单地说,可以在不 重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索关键词联想、用户名是否可用 等校验。

Ajax原理:通过XmlHttpRequest对象来向服务器发送异步请求,从服务器获得数据,然后用JavaScript来操作DOM 而更新页面。要清楚异步请求这个过程和原理,就需要了解XmlHttpRequest。

XmlHttpRequest:客户端把请求交给代理对象—XMLHttpRequest,由代理对象向服务器发起请求,然后接收、解析服务端响应的数据。

  1. 创建XMLHttpRequest对象。
  2. 发送请求,包括设置请求方法和URL,并使用send方法发送请求。
  3. 与服务器通信,服务器根据请求处理并返回响应数据。
  4. 处理响应,通过监听onreadystatechange事件和使用readyState属性来获取请求状态。
  5. 解析响应数据,通过responseText或responseXML属性获取服务器返回的数据。
  6. 更新页面内容,使用JavaScript操作DOM,将数据插入到特定位置,实现局部页面的更新。

在传统的同步请求中,当浏览器发送请求给服务器时,它必须等待服务器处理完请求并返回响应才能进行下一步操作。这意味着用户在请求期间可能会遇到页面冻结或无响应的情况。

而使用Ajax异步请求,浏览器发送请求后,不会等待服务器返回响应,它可以继续处理其他任务,比如用户可以继续浏览页面、与页面进行交互或执行其他JavaScript操作。一旦服务器返回响应,浏览器会触发相应事件或回调函数来处理响应数据并更新页面的特定部分。

5.1 原生Ajax

  1. 准备数据
  2. 创建XMLHttpRequest对象,用于和服务器进行数据交互
  3. 向服务器发送请求
  4. 获取服务器响应数据

点击事件触发执行ajaxRequest()方法,首先构造一个XMLHttpRequest对象,向指定服务端发送一个请求,然后对该请求的状态变化进行监测。readyState保存了XMLHttpRequest对象的状态,为4表示请求已完成且响应已就绪。status是返回请求的状态号,为200表示请求成功。responseText属性表示返回的字符串响应数据。

    <div id="view">
        <p>点击下面的按钮,将 Ajax 请求回来的数据更新在该文本内</p>
    </div>
    <button type="button" id="btn" onclick="ajaxRequest()">发起 Ajax 请求</button>




    <script>
        function ajaxRequest () {
            //1. 初始化代理对象
            var xhr = new XMLHttpRequest();
            
            //2. 发送异步请求
            xhr.open("GET", "https://127.0.0.1/statics/demosource/ajax_info.txt", true);
            xhr.send();
            
            //3. 监测并获取服务端响应数据
            xhr.onreadystatechange = function(){
                if (xhr.readyState === 4 && xhr.status === 200) {
                    document.getElementById("view").innerHTML = xhr.responseText;
                }                
            }
        }
    </script>

5.2 Axios

原始的技术就是通过发送Ajax请求获取服务端的数据,但原生的Ajax比较繁琐,用起来不太方便,开发中一般都用基于Ajax的请求框架,比如Axios。

Axios是一个基于 promise 的网络请求库,可以用于node.js和浏览器。Axios在浏览器使用XMLHttpRequests发送网络请求,并能自动完成JSON数据的转换。安装后就可以在入口文件main.js中导入了,或者在哪个组件使用就在哪个组件导入。

地址:www.axios-http.cn/ 安装:npm install axios 导入:import axios from ‘axios’

安装完成以后axios的依赖包就添加到了node_modules文件下,并在json文件中有记录。

image-20230730100644864.png

vueJS组件开发的中vue对象和组件都有自己的生命周期,并提供有相应的周期函数,而我们发送异步请求的阶段就是前面提到的组件的created阶段:

created: funcation(){//每个组件都有自己的生命周期函数,组件每次被创建时都会调用一次。
    	console.log("组件被创建了!")//在app被挂载之前可以在这里发送axios请求
	},

导入axios,在Book组件中发送axios的get请求,从响应消息对象中可以获取服务端返回的数据属性data,赋值给vue对象中data的相应属性,最后渲染到页面的特定部分。

<template>









    <el-table
      :data="tableData"
      style="width: 100%"
      :row-class-name="tableRowClassName">
      <el-table-column
        prop="title"
        label="书名"
        width="180">
      </el-table-column>
      <el-table-column
        prop="author"
        label="作者"
        width="180">
      </el-table-column>
      <el-table-column
        prop="publisher"
        label="出版社">
      </el-table-column>
    </el-table>
  </template>

  <script>
    import axios from 'axios'
    

    export default {
      created: function(){
        axios.get("http://localhost:8088/user/findAll").then( (response) => {
          console.log(response.data);
          this.tableData = response.data;
        } )
      },
      data(){
          return{
              tableData: []
          }
      },
      methods: {
        tableRowClassName({row, rowIndex}) {
          if (rowIndex === 1) {
            return 'warning-row';
          } else if (rowIndex === 3) {
            return 'success-row';
          }
          return '';
        }
      },
    }
  </script>
    
  <style>
    .el-table .warning-row {
      background: oldlace;
    }
  
    .el-table .success-row {
      background: #f0f9eb;
    }
  </style>
  

在实际的项目开发中,几乎每个组件中都会用到axios发送数据请求。此时会遇到以下问题:

  1. 每个组件中都需要导入axios
  2. 每次发送请求都需要填写完整的请求路径

所以可以通过全局配置的方式解决上述问题。在入口文件main.js中进行配置:

image-20230730104639767.png

这样就可以在任意组件中使用:

created: function(){
        this.$http.get("/user/findAll").then( (response) => {
          console.log(response.data);
          this.tableData = response.data;
        })
      },

在成功回调函数中可以接收一个js对象,通过属性data可以获取服务器响应的数据。

axios.get('/user', {params: {ID: 1234, Name: Bree}})
.then( (response) => console.log(response.data) )
.catch( (error) => console.log(error.data) )
.then( () => 总是会执行 );

6 跨域问题

以上axios发送请求实际上还不能成功获得数据,因为前后端项目的端口不一样,前端发送请求会被浏览器阻止并报错,这就是出现了跨域问题(跨源,不同源)。

在前后端分离项目中:

跨域问题:为了保证浏览器的安全,不同源(同一个域或者局域网中)的客户端脚本在没有明确授予的情况下,不能读写对方的资源,该约定称为同源策略,同源策略时浏览器安全的基石或者核心。所以说要得到服务端的授权才能发送请求。

所以当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同,就称为跨域。此时无法读取非同源网页的Cookie,无法向非同源地址发送AJAX请求。

CORS(Cross-Origin Resource Sharing):即跨域资源共享,是由W3C制定的一种跨域资源共享技术标准,其目的就是为了解决前端的跨域请求问题。通过后端服务器实现CORS接口,从而实现跨域通信。

6.1 解决方法

解决方法就是CORS策略,CORS策略将前端请求分为简单请求和非简单请求,分别对跨域通信提供支持。

简单请求:

对于简单请求,CORS的策略是请求时在请求头(消息头)中增加一个Origin字段Origin: http://localhost:7777,即告诉服务端该请求来自于哪个主机哪个的端口。服务端收到请求后根据该字段判断是否允许该请求访问,如果允许就在响应消息中的响应头(消息头)中加一个Access-Control-Allow-Origin: http://localhost:7777的字段。

非简单请求:

对于非简单请求的跨域请求,浏览器会在真实请求发出前增加一次OPTION请求,称为预检验请求(preflight request)。预检验请求中将真实请求的信息,包括请求方法、自定义头字段、源信息添加到HTTP请求消息的请求头(消息头)中,询问服务器是否允许这些操作。

服务端接收到请求时,需要对Origin、Access-Control-Request-Method、Access-Control-Request-Header进行判断验证,验证通过后会在返回HTTP响应头(消息体)中添加”Access-Control-Allow-XXX: “允许字段信息。

服务端具体的CORS配置:

发送请求之后需要,在传统的Java EE开发中,可以通过过滤器(Filter)统一配置CORS策略。

而在SpringBoot中:

第一种设置跨域策略的方式,只需要在对应的控制器中添加一个@CrossOrigin注解,注解中已对CORS进行默认配置,使得控制器中的所有方法都允许被跨域请求。

第二种方式是通过定义配置类实现WebMvcConfigure接口,在重写方法中设置跨域策略。需要对CORS策略进行精细化控制则使用第二种方式。

7 前端路由VueRouter

Vue路由vue-router是官方的路由插件(土一点说就是用来设置和管理超链接的),能够轻松的管理SPA项目(单页Web应用)中组件的切换,实现组件页面的跳转,单独展现出不同的组件页面。Vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。vue-router目前有3.x版本和4.x版本,3.x版本结合vue2进行使用,4.x版本结合vue3进行使用。

组成:

vuerouter对象:路由表,根据路由请求在路由视图中动态渲染选中的组件

router-link:请求链接组件,浏览器会解析成超链接

router-view:动态路由组件,用来渲染展示与路由路径对应的组件

7.1 VueRouter安装

安装:npm install vue-router@3,安装vue-router3最新的版本

7.2 创建路由组件

接下我们通过路由来开发和管理单页面应用QQ音乐部分组件,可以将想看组件页面单独展现出来。

image-20230730173318820.png

在项目中定义Musichall.vue、Mymusic.vue两个组件,将来要使用vue-router来控制它们的展示和切换:

Musichall.vue

<template>









    <div>





        <h1>音乐馆</h1>

    </div>

</template>

Mymusic.vue

<template>









    <div>





        <h1>我的音乐</h1>
    </div>

</template>

7.3 声明路由链接和占位符

创建好两个组件后,不用直接导入和注册到App.vue中全部显示,而是在App.vue中使用标签来声明路由链接,并使用标签来声明路由占位符,这样就可以实现在单页面下动态地进行组件的切换和单独展示:

	<!-- 声明路由链接,并未设置链接与组件的对应关系 -->
    <router-link to="/musichall">音乐馆</router-link>
    <router-link to="/mymusic">我的音乐</router-link>
    <!-- 声明路由占位标签 -->
    <router-view></router-view>

7.4 创建路由模块

然后在项目中router文件夹下创建index.js路由模块,设置路由链接与组件的对应关系:

import VueRouter from 'vue-router'
import Vue from 'vue'
import Musichall from '../components/Musichall'
Vue.use(VueRouter)




// 在index.js文件中设置路由链接与组件的对应关系,注意对应关系属性名称是routes
const router = new VueRouter({
    //指定hash属性path与组件的对应关系
    routes: [
        {path: '/musichall', component: Musichall},
        //通过以下直接引入也行
        {path: '/mymusic', component: () => import Mymusic from '../components/Mymusic'}
    ]
})

export default router//导出对应关系,然后在入口文件main.js中导入加同vue对象一起加载才生效。

最后再导入和设置路由使其在vue对象中生效:

import Vue from 'vue'

import App from './App.vue'

import router from './router/index'





Vue.config.productionTip = false


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

这样如Musichall组件与在App.vue中声明的路由链接”/musichall”一一对应起来,这样以后在App.vue组件页面中切换到该链接,就会显示Musichal组件的页面信息,也就是router-view占位符的地方。

7.5 路由重定向

路由重定向指的是:如用户在访问根组件的时候,默认用户重定向到根组件下的相应组件,从而展示特定的组件页面。通过路由规则的redirect属性,指定一个新的路由地址,可以很方便地设置路由地重定向:

const router = new VueRouter({
    //指定hash属性path与组件的对应关系
    routes: [
        {path: '/', redirect: '/musichall'},
        {path: '/musichall', component: Musichall},
        {path: '/mymusic', component: Mymusic}
    ]
})

7.6 嵌套路由

在Musichall组件中,可以声明topist和playlist地子路由链接以及子路由占位符:

<template>









    <div>





        <h1>音乐馆</h1>

        <!-- 子路由链接 -->
        <router-link to="/musichall/playlist">首页</router-link>
        <router-link to="/musichall/singers">歌手</router-link>
        <hr>
        <router-view></router-view>
    </div>
</template>

在index.js路由对应关系文件中,导入需要的组件,并使用children属性声明子路由规则:

// 在index.js文件中设置路由链接与组件的对应关系
const router = new VueRouter({
    //指定hash属性path与组件的对应关系
    routes: [
        {path: '/', redirect: '/musichall'},


        {path: '/musichall', component: Musichall,
         children: [
            {path: 'playlist', component: Playlist},//注意子路由不用加'/'
            {path: 'singers', component: Singers},
         ]
        },



        {path: '/mymusic', component: Mymusic},
    ]
})

7.7 动态路由

假设有如下图的几行歌手,点进去都是每个歌手各自的详情页面,但我们不可能为每一个歌手都创建一个歌手详情组件页面。而是重用组件的模板页面,当点击一个歌手时,从后台获取相应的数据,然后在传给组件中的属性,最终显示出来。

image-20230730210207896.png

动态路由是指:把Hash地址中可以改变的部分定义为参数项,从而提高路由规则的复用性。在vue-router中使用英文的冒号(:)来定义路由的参数项(Musichall->Playlist->Detail三级路由):

{path: '/musichall',
         component: Musichall,
         children: [
            {path: 'playlist', component: Playlist},




            {path: 'singers', 
             component: Singers,
            children: [
                {path: ':id', component: Detail}
            ]
            },
         ]
        },

通过动态路由匹配的方式渲染出来的组件中,可以使用$router-.params对象访问到动态匹配的参数项,比如在歌手详情组件内部页面根据id值,请求不同的歌手数据:

<template>









    <h1>歌手详情页{{ $route.params.id }}</h1>
</template>

当然可以不通过$route.params.id获取参数,vue-router允许在路由规则中开启props传参,在组件内部定义属性:

<template>









    <h1>歌手详情页{{ id }}</h1>
</template>






<script>
export default{
    name: 'Detail',
    props: [":id"],
}


</script>

然后在路由映射中说明id以属性传递给组件:

{path: ':id', component: Detail, props: true}

7.7 编程式路由导航

声明式 编程式
router-link router.push(“…”)

除了使用创建a标签来定义导航链接,还可以借助router的实例方法,通过编写代码来实现。

<template>









    <div>





        <h2>万千歌手,尽在眼前</h2>
        <button @click="gotoSingerDetail(1)">跳转到歌手1</button>
        <router-view></router-view>
    </div>

</template>



<script>

export default{

    methods: {
        gotoSingerDetail(id){
            this.$router.push("/musichall/singers/${id}")
        }
    }
}
</script>

想要导航到不同的路由(URL),则使用router.push(“…”)方法。这个方法会向history栈添加加一个新的记录,所以当用户点击浏览后后退按钮时,会回到之前的URL。

当点击时,这个方法会在内部调用,所以说点击等同于调用router.push(“…”)

7.7 导航守卫(拦截器)

路由守卫可以控制路由的访问权限,类似于后端拦截器。

全局路由导航守卫会拦截每一个路由,从而对每个路由进行访问权限的控制。可以在路由配置模块中使用router.beforeEach注册一个全局前置导航守卫:

router.beforeEach( (to, from, next)=>{
    if(to.path==='/main' && !isAuthenticated){//to: 即将进入的目标, from: 当前路由
        next('/login')
    }
    else{
        next()//在参数中声明next形参后必须调用next()函数,否则从当前路由不允许访问任意路由
        	  //next():直接放行;next(false):强制停留在当前路由;next('/login'):强行跳转。
    }

})

8 状态管理Vuex

状态管理一般用在复杂的大型项目中才会用到,也就说在一般的网站中Vuex不是必须的。

对于组件化开发来说,大型应用的状态往往跨越多个组件。在多层嵌套的父子组件之间传递数据状态已经十分麻烦,而Vue更是没有为兄弟组件提供直接共享数据的办法。基于这个问题,许多框架提供了解决方案——使得全局的状态管理器,将所有分散的共享数据交由状态管理器保管,Vue框架也是这样。

Vuex就是一个专门为Vue.js应用程序开发的状态管理库,采用集中式存储管理应用的所有组件的状态。简单地说,Vuex用于管理分散在Vue各个组件中的数据。

Vue2和Vue3分别对应VueX3和VueX4版本

安装:npm install vuex@next,安装next的最新版本

每一个Vuex应用的核心都是一个全局实例store,与普通的全局对象不同的是,基于Vue数据与视图绑定的特点,当store中的数据状态发送变化时,与之绑定的视图也会被重新渲染。store中的状态不允许被直接修改,改变store中的状态的唯一途径就是显式地提交mutation,这样可以让我们方便地跟踪每一个状态的变化。

在大型复杂项目中,如果无法有效地跟踪到状态的变化,将会对理解和维护代码带来极大的困扰。

Vuex中有五个重要的概念:State、Getter、Mutation、Action、Module。

image-20230731160038386.png

store中state的数据发送变化时可以被重新渲染到Vue组件中,或者当Vue组件发送网络的异步请求时,会通过dispatch派遣的方式去触发action发送异步请求获取数据,然后通过提交Mutation中的方法将对应的数据修改为新的数据,实现对state数据状态的改变,最终渲染到Vue组件页面中。

8.1 State与Mutation和Action

State用于维护所有应用层的数据状态,并确保应用只有唯一的数据源;Mutation中定义数据修改方法;Action类似于Mutation;Getter用来进一步监测维护由State派生的一些数据状态。

首先我们在项目中store文件夹下创建一个js文件,导入vuex后显示地通过Vue.use(Vuex)来安装Vuex,安装之后就可以创建store了:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)





const store = new Vuex.Store({//Vue2(VueX3):new Vuex.Store
    state (){
        return {
            //所有的数据都可以定义到state中去共享
            count: 2, 
            todos: [
                {id: 1, name: "学习", done: true}, //待办事项已完成
            	{id: 2, name: "运动", done: true}, //待办事项未完成
                {id: 3, name: "吃饭", done: false},
                {id: 4, name: "睡觉", done: false}
            ]
        }
    },
    
    mutations: {
        increment (state, n){//可以加n载荷也可以不加,在组件中直接提交
            state.count+=n //基于Mutation在其中修改数据状态,外部只要调用increment()方法就可以对								 store中的数据状态state进行修改。
        }

    },
    
    actions: {
        increment (context){
            context.commit('increment');
        }
    },
    

    getters: {
        doneTodos: state => {
            return state.todos.filter(todo => todo.done) //过滤出所有已完成的并返回
        }
    }
    
})

export default store //导出,然后还需要在入口文件main.js导入并注册到vue对象中,方便任意组件使用store取数据

在模块化的构建系统中,在每个需要使用state的组件中需要频繁地导入。Vuex通过store选项,提供了一种机制将store从根组件”注入”到每个子组件中,在入口文件中从上面写好的js文件导入和注册Vuex对象store:

import Vue from 'vue'

import App from './App.vue'

import store from './store/index.js'





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

这样在任意组件中就可以利用store对象获得state:

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

8.2 在组件中改变和获得store的状态

提交Mutation中的方法改变store的状态,在main.js文件中导入和注册store对象后,组件中就可以直接使用this.store.commit(...)显式地提交mutation改变store中的状态,或者通过mapMutations映射的方式隐式提交,然后在计算属性中直接使用this.store.commit(“…”)显式地提交mutation改变store中的状态,或者通过mapMutations映射的方式隐式提交,然后在计算属性中直接使用this.store.state.count或者通过mapState映射的方式:

<template>









	<div>
        <!-- {{this.$store.state.count}} -->
        <!-- 以上数据变化可以通过计算属性会监听并返回 -->
        {{count}}
        <button @click="plus(2)"> +2 </button><!-- plus方法中通过显示提交,定义plus和提交时需要显示传递参数 -->
        <button @click="add(4)"> +4 </button> <!-- 在add通过映射的方式提交,定义add时会自动传递 -->
        
        <!-- mapState -->
        <ul>
            <li v-for="todo in todos" :key="todo.id">事项{{todo.id}}{{todo.name}}</li>
    	</ul>
        <!-- mapGetters获取已完成事项 -->
        <ul>
            <li v-for="todo in doneTodos" :key="doneTodos.id">已完成事项{{todo.id}}{{doneTodos.name}}</li>
    	</ul>
    </div>
</template>


<script>
import {mapState, mapGetters, mapMutations} from 'vuex'
    
export default {
    //在vue的计算属性定义映射方法,监听并返回某个数据状态,可以不用data属性返回
    

    computed: {
        count(){
        	return this.$store.state.count
        },
    

    	//可以通过mapState辅助函数获取多个数据状态
    	//mapState已经做导入,不用通过this.$store.mapState调用
        ...mapState([  //"..."表示使用对象展开运算符将 State 混入 computed 对象中

            //通过属性传递简化写法mapState([])
            'count',
            'todos',
            
            //通过将方法传递到对象中mapState({})获取状态
            //count: state => state.count,
            //todos: state => state.todos,

            //为了使用'this'获取局部状态,必须使用常规方法,通过将方法传递到对象中mapState({})获取
            //countPlusLocalState(state){
            //    return state.count + this.localCount
            //}
        ]),
    
    	//可以提供通过mapGetter辅助函数获取多个state中已完成事项
    	//mapGetter已经做导入,不用通过this.$store.mapGetter调用
    	...mapGetters([// 使用对象展开运算符将 getter方法 混入 computed 对象中
            'doneTodos',
        ])
    },
    
    methods: {
        //在普通函数中提交store的状态state,改变store中状态state的唯一途径就是显式地提交mutation
        plus(n){
            this.$store.commit("increment", n) //提交时可以传入数据,数字,字符串或者对象
        },
        
        //可以在mapMutations辅助函数中的定义多个方法映射提交修改对应数据状态的方法。
        //通过提交Mutation中的方法修改store中的状态state
        ...mapMutations({  //"..."表示使用对象展开运算符将 Mutation 混入 methods 对象中
            add: 'increment', //将this.add()映射为this.$store.commit('increment')

            //'incrementBy',     //将this.incrementBy()映射为this.$store.commit('incrementBy'),通过属性传递mapMutations(['incrementBy'])
        })
	}
}
</script>

定义组件路由,启动显示:

image-20230802121247223.png

Action类似Mutation,不同在于:

Action不是直接改变状态,而是通过上下文对象提交mutation来间接地修改state中的数据状态,context中可以记录操作,Action可以包含异步操作。

在组件中,可以通过使用this.$store.dispatch(‘xxx’)触发action中的’increment(context)’方法,或者使用mapActions辅助函数先将其映射下来。

methods: {
 increment(){
     this.$store.dispatch('increment');
     //或者
     mapActions([
       'increment', //将'this.increment()'映射为'this.$store.dispatch('increment')'
     ])
 }
}


在组件中,调用Getter中的方法可以直接使用this.$store.getter.doneTodos:

methods: {
    add(){
        this.$store.commit('increment'); //通过提交Mutation中的方法将对应的数据修改为新的数据
        console.log(this.$store.state.count);
    },
    getter(){
        this.$store.getter.doneTodos
    }

}


8.3 Module

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。

为了解决以上问题,Vuex允许我们将store分割成模块(modules)。每个模块拥有自己的state、mutation、action、getter,最后在创建store对象时在modules属性中映射模块,该模块就称为了store对象的state:

const moduleA = {
    state: () => ({...}),
    mutations: {...},
    actions: {...},
    getters: {...}
}
const moduleB = {
    state: () => ({...}),
    mutations: {...},
    actions: {...},
    getters: {...}
}
const store = createStore({//Vue2(VueX3):new Vuex.Store
    modules: {
        a: moduleA,
        b: moduelB
    }

})



//store.state.a => moduleA.state
//store.state.b => moduleB.state

9 MockJS前端数据模拟

9.1 基本使用

Mock.JS是一款前端开发中拦截Ajax请求再生成随机数据响应的工具,可以用来模拟服务器的数据响应。优点是简单方便,无侵入性,基本覆盖常用的接口数据类型。支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等。MockJS只是在前端的开发阶段会使用,当后端接口开发完成后只需移除即可,方便于前后端独立开发。

安装:npm install mockjs

在项目中创建mock文件夹,新建js文件,导入Mock,通过Mock.mock(‘url’, data )方法生成数据,数据生成规范包含两层规范,数据模板(DTD)、数据占位符(DPD较常用):

//引入mockjs
import Mock from 'mockjs'




//使用mockjs模拟数据
//第一个参数为对指定请求路由(url)的拦截,如果拦截的请求中传递有参数,/musichall/singers?id=1,或通过设置props: true传递属性。拦截的url可以通过正则表达式对应请求的url。".*": 表示任意字符。
Mock.mock(RegExp('/musichall/singers.*'), { 
    "ret": 0,
    "data": {
        //通过占位符随机生成日期和中文名字,占位符只是在属性值字符串中占个位置,并不出现在最终的属性值中
        //当我们使用@datetime这样的占位符时会调用Mock.Romdom生成随机数据的工具类中的方法
        "mtime": "@datetime",
        "nickname": "@cname", 
        //通过数据模板随机生成1-10的数字,'1'仅代表生成数据的类型
        "score|1-10": 1,
        //生成图片,长宽、背景颜色、文字颜色、图片类型、图片中的文本
        "img": "@image('200x200', '#ffcc33', '#FFF', 'png', '生成图片')" //注意乘号
    }

})

然后在入口文件main.js中导入,当后端接口开发完成后只需移除即可:

import './mock'

组件中通过axios发送异步请求,然后会调用mockjs中模拟的数据接口进行拦截,这时返回的response中的data就是mockjs中用Mock.mock(‘url’, data)中生成的ret和data:

<template>









    <div>





        <!-- 获取动态的id值 -->
        <h1>歌手详情{{ id }}</h1>
        <img alt="singer" :src="img">
    </div>

</template>



<script>

export default{

    props: ["id"],
    created: function(){
        this.$http.get("/user/findAll").then( (response) => {
          console.log(response);
          console.log(response.data.data.img);
          this.img = response.data.data.img
        })
      },
    data: function(){
        return {
            img: ""
        }

    }
}
</script>

获取显示成功:

image-20230801151400565.png

image-20230801150919658.png

10 Vue-Element-Admin

10.1 下载和安装

Vue-Element-Admin是一个后台前端管理解决方案,它基于vue和element-ui实现。内置i18国际化解决方案,动态路由,权限认证,提炼了典型的业务模型,提供了丰富的功能组件。可以快速搭建企业级中后台产品原型。

地址:

panjiachen.github.io/vue-element…

Vue-Element-Admin是后台集成方案,不太适合当基础模板来进行二次开发因为可能集成了很多自己用不到的功能,造成不少代码冗余。如果项目简单可以基于vue-element-template基础模板开发。

因为该项目开源在Github和Gitee上,可以通过Git工具进行克隆

git clone https://github.com/PanJiaChen/vue-element-admin.git #克隆集成模板
git clone https://gitee.com/panjiachen/vue-admin-template.git #克隆基础模板
#进入项目目录
cd vue-element-admin
#安装依赖
...

或者通过vscode打开,然后进行依赖的安装:

# 安装依赖,可能会安装失败
npm install




# 建议不要用 cnpm 安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npmmirror.com

注意,Windows安装依赖不成功,是因为项目中开发阶段使用的工具中包含sass,就像前面使用VueCli脚手架构建项目时,取消选择的eslint开发阶段工具。因为 node-sass 是依赖 python2的环境的,如果之前没有安装和配置过的话,sass会安装失败,需要自行安装配置一下。

该模板项目也用到了eslint,如果不想使用eslint校验(不推荐取消),只在vue.config.js文件设置以下属性即可:

lintOnSave: false

10.2 启动项目

在package.json文件中的JavaScript脚本属性值”vue-cli-service serve”的属性名改为了”dev”,也就启动时将npm run serve改为npm run dev即可。

npm run dev

另外,通过浏览器访问该项目默认端口是9527,要切换可以在模块导出中的devServer修改port属性。devServer用来在系统中配置我们的开发环境,只是用于本机开发和调试,一般打包发布之后就用不到了。

10.3 项目的理解

以登录过程为例:

  1. 用户提交登录信息后通过dispatch触发action
  2. action会进行表单信息的校验,通过调用api中的接口访问服务端
  3. 校验通过后会提交mutation修改state数据状态
  4. getter会获取store的最新状态,并渲染到组件页面中。

在src目录下,包含components、views、router、store等几个重要的目录。

router目录,也就是用于设定访问路径,并将路径和组件映射起来,实现在页面中进行组件的切换和显示。其中index.js文件用于设定组件和子组件的访问路径,将路径和组件映射关联起来。可以说路由就是组件。

其次是components和views目录,其中关于页面相关的组件都是放在views下,而components下一般放一些通用(可复用)的组件。在组件中可以提交改变相关状态dispatch方法。

store目录,也就是前面说的Vuex状态管理的核心,组件中的数据状态都由全局实例store管理。在Index.js文件中创建store对象时在modules属性中映射了app、settings、user三个模块,管理着各自模块状态的改变。在组件中调用dispatch派遣的方式触发和传递相关数据给store中的actions方法和,在actions中调用相应的网络请求接口并传递数据。

api目录中的js文件就是封装了相应aixios网络请求接口,用来接收参数包括路由、请求方法、数据。

最后在utils目录中的request.js文件更具体地进行axios网络请求。所以一切的开头是组件,然后通过Vuex的store一层层的改变状态,最后在utils中向服务端发送请求。

除以上之外,还有layout目录中做相关的组件布局,styles目录中放样式文件(scss),assets目录中放了一些图片,icons目录中放了一些图标。

11 打包部署

11.1 打包

执行NPM脚本程序build:

image-20230802095339107.png

或者直接打开终端:npm run build

已经成功打包在dist目录下:

image-20230802095723536.png

11.2 部署

Nginx是一款轻量级的wen服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。其特点是占有内存少,

并发能力强,在各大型互联网公司都有非常广泛的使用。

官网:nginx.org/

进入官网下载软件包后解压:

conf:配置文件目录
html:静态资源文件目录 logs:日志文件目录 
temp:临时文件目录 nginx.exe:nginx可执行文件

部署静态资源:

部署:将打包好的dist目录下的文件全部复制到nginx安装目录的html目录下。

启动:双击nginx.exe文件即可,Nginx服务器默认占用80端口号。如果80端口号被系统占用(netstat-ano|findStr 80),可以在nginx.conf中修改端口号为xxx。

访问:http://localhost:xxx

当然Nginx功能非常强大,这里只是演示一下在Nginx上部署静态资源,后面还学通过Nginx怎么做反向代理,如何实现负载均衡。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYpEPLIa' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片