Vue组件化响应式编程介绍
Vue.js是一款流行的JavaScript框架,它支持组件化和响应式编程。组件化是一种将用户界面划分为独立可复用的模块的开发方式,而响应式编程则允许数据的变化自动更新视图,提高开发效率。Vue.js巧妙地结合了这两个概念,下面将介绍Vue组件化和响应式编程的关键特性。
Vue组件化使得应用程序的开发更加模块化和可维护。一个Vue应用由一个个小的组件组成,每个组件都有自己的状态和行为。这种模块化的开发方式使得团队可以更容易地分工合作,每个成员专注于开发和维护特定的组件,而不必担心整个应用的复杂性。组件可以嵌套在其他组件中,形成清晰的层次结构,使得代码更具可读性和可扩展性。
Vue的响应式编程机制使得数据与视图之间建立了自动的关联。当数据发生变化时,与之相关的视图会自动更新,而无需手动操作DOM。这是通过Vue的数据绑定和响应式系统实现的。开发者只需要关注数据的变化,Vue会负责更新与之相关联的视图,大大简化了开发流程。这种响应式的特性使得开发者能够更专注于业务逻辑,而不必过多考虑视图的更新问题。
在Vue中,一个组件通常由三个部分组成:模板(Template)、脚本(Script)和样式(Style)。模板定义了组件的结构,脚本包含了组件的逻辑和状态,样式则定义了组件的外观。这三者通过Vue的单文件组件(.vue文件)的形式进行组织,使得组件的代码更加清晰有序。
在脚本部分,开发者可以使用Vue提供的数据绑定语法,将数据与视图进行关联。当数据发生变化时,相关的视图会自动更新,实现了响应式编程。开发者还可以通过计算属性(computed properties)和监听器(watchers)等特性来更灵活地控制数据和视图之间的关系。
Vue中的异步调用
异步调用在Vue中的应用是前端开发中不可或缺的一部分,它涉及到处理异步操作,如数据请求、定时器、事件处理等。Vue结合了各种异步处理方式,包括Callback函数、Promise对象以及async/await等,以便更好地管理和组织异步代码。
Callback函数是一种基本的异步处理方式,它在Vue中被广泛应用。通过Callback函数,可以定义一个回调函数,在异步操作完成后调用该函数。在Vue中,常见的异步操作包括数据请求,比如使用Vue的$http
或者axios
库来获取数据。通过Callback函数,可以在异步数据加载完成后执行相应的逻辑,确保数据准备就绪后再进行界面更新。例如:
created() {
this.getData(this.handleData);
},
methods: {
getData(callback) {
// 异步请求数据
this.$http.get('/api/data').then(response => {
// 数据加载完成后执行回调
callback(response.data);
});
},
handleData(data) {
// 处理数据逻辑
this.data = data;
}
}
其次,Promise对象是一种更为灵活和可组合的异步处理方式,它在Vue中也得到广泛应用。Promise对象可以处理复杂的异步操作流程,使得代码更加清晰和易于维护。例如,在数据请求中使用Promise对象可以更好地处理异步链式调用:
created() {
this.getData()
.then(data => {
// 处理数据逻辑
this.data = data;
})
.catch(error => {
// 处理错误逻辑
console.error(error);
});
},
methods: {
getData() {
// 返回一个Promise对象
return new Promise((resolve, reject) => {
this.$http.get('/api/data').then(response => {
// 异步请求成功,调用resolve传递数据
resolve(response.data);
}).catch(error => {
// 异步请求失败,调用reject传递错误信息
reject(error);
});
});
}
}
Vue中的Ajax
在Vue.js中,通常会使用ajax(Asynchronous JavaScript and XML)来进行异步数据请求,而axios是一个强大且广泛使用的HTTP客户端库,用于发起HTTP请求。在Vue项目中,对axios进行封装是一种常见的实践,这样能够更好地组织和管理代码,提高代码的可维护性和可复用性。
封装axios的一个主要目的是为了在应用中创建自定义的API调用函数,使其更符合项目的需求,并提供一致的接口。以下是一个Vue中axios封装的例子:
// 在src/utils/http.js中封装axios
import axios from 'axios';
// 创建axios实例
const instance = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL, // API基础路径
timeout: 5000, // 请求超时时间
});
// 封装GET请求
export const get = (url, params) => {
return instance.get(url, { params });
};
// 封装POST请求
export const post = (url, data) => {
return instance.post(url, data);
};
// 在Vue组件中使用
import { get, post } from '@/utils/http';
export default {
created() {
// 发起GET请求
get('/api/data', { param1: 'value1' })
.then(response => {
// 处理响应数据
console.log(response.data);
})
.catch(error => {
// 处理错误
console.error(error);
});
// 发起POST请求
post('/api/postData', { key: 'value' })
.then(response => {
// 处理响应数据
console.log(response.data);
})
.catch(error => {
// 处理错误
console.error(error);
});
},
};
专题实验:一个简单的 Vue + SpringBoot 的在线多人匿名聊天的网站
前端登录界面的搭建
登录通过昵称登录,其中的template标签代码如下:
<template>
<div class="name">
<el-form
class="name-form"
ref="nameFormRef"
:model="nameForm"
:rules="nameRules"
@submit.prevent
>
<el-form-item>
<h1>多人群聊系统</h1>
</el-form-item>
<el-form-item class="name-input" prop="nickname">
<el-input
class="nickname"
v-model="nameForm.nickname"
@keydown.enter="submitButton(nameFormRef)"
placeholder="输入一个昵称"
></el-input>
<el-button
class="submit"
type="primary"
@click="submitButton(nameFormRef)"
>进入</el-button
>
</el-form-item>
</el-form>
</div>
</template>
其中用户名从前端传递到后端,后端服务器对其进行校验,若不存在则将username加入session,否则,前端判空,提示用户,用户名重复。
前端代码如下:
// 昵称表单
const nameFormRef = ref<FormInstance>();
// 昵称表单
const nameForm = reactive({
nickname: "",
});
// 表单校验
const nameRules = reactive<FormRules>({
nickname: [{ required: true, message: "请输入一个昵称", trigger: "blur" }],
});
// 登录操作
const submitButton = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate((valid) => {
if (valid) {
axios
.get("http://localhost:8888/list/" + nameForm.nickname)
.then((resp) => {
const data = resp.data;
// 判断用户名是否存在
if (!data.isExist) {
sessionStorage.setItem("name", nameForm.nickname);
router.push("/chat");
} else {
ElMessage({
message: "该用户名已存在,请更换",
grouping: true,
type: "error",
});
}
});
} else {
ElMessage({
message: "请输入一个昵称",
grouping: true,
type: "error",
});
return false;
}
});
};
后端控制器代码如下:
@GetMapping("/{username}")
public JSONObject getUsername(@PathVariable("username") String username) {
JSONObject jsonObject = new JSONObject();
boolean isEmpty = sessionMap.isEmpty();
jsonObject.put("isEmpty", isEmpty);
jsonObject.put("isExist", false);
if (!isEmpty) {
boolean isExist = sessionMap.containsKey(username);
jsonObject.replace("isExist", isExist);
}
return jsonObject;
}
(后端开放8888端口供前端访问,把登录的用户存到 sessionMap 中)
通过websocket访问后端数据
WebSocket是一种在单个持久连接上进行全双工通信的协议,它能够在客户端和服务器之间实现实时、低延迟的数据传输。在Java中,有多种方式可以实现WebSocket通信,其中比较常用的是使用Java API for WebSocket(JSR-356)和Spring框架提供的支持。
前端需要开启websocket服务,绑定后端服务端口,设置url地址。
// 开启 WebSocket 服务
let socketHost = "localhost";
let socketPort = "8888";
let socketUrl =
"ws://" + socketHost + ":" + socketPort + "/socket/" + nickname.value;
socket = new WebSocket(socketUrl);
前端设置websocket的代码如下:
// 连接服务器
socket.onopen = () => {
console.log("已连接至服务器");
};
// 浏览器接收服务端发送的消息
socket.onmessage = (msg) => {
let data = JSON.parse(msg.data);
if (data.userlist) {
// 接收用户列表消息
userList.value = data.userlist;
userCount.value = data.userlist.length;
} else {
// 接收消息
messages.value.push(data);
// 获取节点
let chatHistory = document.getElementsByClassName("chat-message")[0];
if (chatHistory.scrollHeight >= chatHistory.clientHeight) {
setTimeout(function () {
//设置滚动条到最底部
chatHistory.scrollTop = chatHistory.scrollHeight;
}, 0);
}
}
};
// 关闭服务
socket.onclose = () => {
console.log("WebSocket 服务已关闭");
};
// 错误事件
socket.onerror = () => {
console.log("WebSocket 服务发生错误");
};
});
服务器端有四个方法:
@OnOpen //当链接创建时调用的
@OnMessage //当接收到消息时调用的
@OnClose //当链接关闭时调用的
@OnError //当链接发生异常时调用的
其中onopen,onclose,onmessage,onerror,在服务端对应的代码如下:
@OnOpen
public void onOpen(Session session, @PathParam("username") String username) {
// 搜索名称是否存在
boolean isExist = sessionMap.containsKey(username);
if (!isExist) {
System.out.println(username + "加入了聊天室");
sessionMap.put(username, session);
sendAllMessage(setUserList());
showUserList();
}
}
/**
* WebSocket 关闭连接事件
* 1.把登出的用户从 sessionMap 中剃除
* 2.发送给所有人当前登录人员信息
*/
@OnClose
public void onClose(@PathParam("username") String username) {
if (username != null) {
System.out.println(username + "退出了聊天室");
sessionMap.remove(username);
sendAllMessage(setUserList());
showUserList();
}
}
/**
* WebSocket 接受信息事件
* 接收处理客户端发来的数据
* @param message 信息
*/
@OnMessage
public void onMessage(String message) {
Message msg = JSON.parseObject(message, Message.class);
sendAllMessage(JSON.toJSONString(msg));
}
/**
* WebSocket 错误事件
* @param session 用户 Session
* @param error 错误信息
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
后端OnOpen将新加入的成员的username加入sessionMap中、OnClose将退出的用户从sessionMap中移除。OnMessage中的方法如下:
/**
* 发送消息到所有用户中
* @param message 消息
*/
private void sendAllMessage(String message) {
try {
for (Session session : sessionMap.values()) {
session.getBasicRemote().sendText(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
前端从message中取出消息并展示
聊天界面如下所示:
实验总结
在这个实验中,我成功地搭建了一个简单而高效的多人聊天系统,前端采用Vue框架,后端使用Java实现WebSocket通信。这个实验不仅帮助我深入了解了前后端协同工作的原理,还锻炼了我的编程和系统设计能力。
首先,在前端方面,Vue的使用使得界面的构建变得简单而灵活。Vue的组件化开发模式使得前端代码更加清晰,易于维护。通过Vue的双向数据绑定,我能够实时更新聊天界面,使用户能够及时看到其他用户的消息。Vue的生命周期钩子函数也为页面的初始化和销毁提供了便捷的方式,确保页面的稳定运行。
在后端方面,Java WebSocket的运用让我更好地理解了实时通信的实现原理。通过使用Java API for WebSocket,我能够轻松创建WebSocket端点,实现与前端的双向通信。通过WebSocket的持久连接,服务器可以将消息实时推送到所有连接的客户端,从而实现多人实时聊天。
在整个实验过程中,我学到了许多关于前端和后端协同工作的经验。前端和后端的分离使得系统更容易扩展和维护。同时,通过WebSocket的使用,我也深刻理解了实时通信在现代Web应用中的重要性。