Vue2
局部刷新
1,app.vue 中局部刷新
<template>
<div id="app">
<router-view v-if="isShow" />
</div>
</template>
<script>
export default {
name: "App",
provide() {
//父组件中通过provide来提供变量,在子组件中通过inject接受。
return {
reload: this.reload,
};
},
data() {
return {
//自定义参数
isShow: true,
};
},
methods: {
// 刷新
reload() {
//reload方法首先将isShow设置为false,将router-view通过if判断取消
this.isShow = false;
// Vue.nextTick用于延迟执行一段代码,它接受2个参数(回调函数和执行回调函数的上下文环境),如果没有提供回调函数,那么将返回promise对象。
this.$nextTick(function () {
// 在页面更新后再将isShow设置为true
this.isShow = true;
});
},
},
};
</script>
2,使用得页面中
export default {
inject:['reload'],// 此处引入在app中定义的reload方法
name: 'Home'
}
3,接口调用事件
methods: {
// 右键事件
delLink(item,e){
delLink(item.id).then(res=>{
if (res.data.code === 200) {
console.log("->",res.data);
this.$message({
message: '删除成功',
type: 'success'
});
this.reload(); // 主要 主要 主要
}
}).catch(res=>{console.log("delLink->error")})
},
路由history打包后页面空白
vue默认路由模式为 hash,一般打包不会有问题,hash模式url中会带有 #
history模式下,如果项目直接放在根目录下,打包也不会出现什么问题,非根目录的项目需要加上base 的路径
vue router配置
const router = new VueRouter({
mode: "history",//路由模式
base: '/justMe',//项目路径
routes: routes,
scrollBehavior(to, from, savedPosition) {
return {x: 0, y: 0}
}
})
nginx配置
项目指定打包放在根目录
location / {
try_files $uri $uri/ /index.html;
}
如果不是根目录访问
location /justMe {
root /apps/justMe;
index index.html index.htm;
#error_page 404 /history/index.html;
if (!-e $request_filename) {
rewrite ^/(.*) /justMe/index.html last;
break;
}
}
数据更新,页面未更新
解决:页面dom元素加 if 判断
V-if="tableList.length>0"
Vuex
state :提供唯一的公共数据源,所有共享的数据统一放到store的state进行储存,相似与data
Action:提交提交到mutation中,而不是直接变更状态,总是接受 context
作为第一个参数,payload
作为第二个参数(可选), 可用es6语法解构出 commit,state,dispatch等属性
Mutation:更改 Vuex 的 store 中的状态的唯一方法,总是接受 state
作为第一个参数,payload
作为第二个参数(可选)
const store = new Vuex.Store({
state: {
count: 1,
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
mutations: {
increment (state,num) {
// 变更状态
state.count+=num
}
},
actions: {
//这里是用了es6解构语法 从context中解构出commit
increment ({ commit },num) {
commit('increment',num)
}
}
})
组件 –dispatch–> Actions
Action中触发其他Module的Action
dispatch('tagsView/delAllViews', null, { root: true })
触发tagsView这个Module中Actions的delAllViews方法
组件中 :this.$store.dispatch("increment")
Actions–commit–>Mutation
组件中
this.$store.commit("increment",10)
调用了Mutation的increment方法
Mutation –更改–> State
state.count+=num
State —-渲染—-> 组件
this.$store.state.count
Getters
接受 state 作为其第一个参数, 也可以接受其他 getter 作为第二个参数
组件中使用:
this.$store.getters.doneTodosCount
Module
Vu3+TS
节流
1,新建preventReClick.ts
import { App } from 'vue'
export const setupPreventReClickDirective = (app: App<Element>) => {
//自定义指令 preventReClick
app.directive(
'preventReClick',
//自定义节流操作
{
mounted(el: any, binding: any) {
el.addEventListener('click', () => {
if (!el.disabled) {
console.log('true')
el.disabled = true
setTimeout(() => {
el.disabled = false
}, binding.value || 500) //500ms间隔时间
}
})
}
}
)
}
2,main.ts添加
// 创建实例
const setupAll = async () => {
const app = createApp(App)
//引用
setupPreventReClickDirective(app)
app.mount('#app')
}
3,页面使用
<ElButton @click="cancelClick" v-preventReClick="1000" v-if="showCancel">{{ cancelText }}</ElButton>
Ref
在Vue 3中,使用ref获取组件实例时,需要使用.value来访问实例,ref是一个非常有用的特性,可以帮助我们更方便地操作DOM元素或组件实例
<h2 id='a'>馒头</h2>
传统中要获取h2这行元素 document.getElementById('a')
<h2 ref='a'>馒头</h2>
vue中可以
import {ref} from 'vue'
let a = ref() //用于存储ref标记的内容
console.log(a.value) // 输出馒头
-------------------------------
js中
let count = ref(1)
console.log(count.value) // 输出 1
// 如果需要传递 count 到某个不接受 ref 的地方,可以使用 unref
unref(count) 会返回 count.value 的值,即 1
defineExpose
defineExpose => 组件向外暴露的自身的属性和方法
组件的内部状态和方法默认是私有的,只能在组件内部使用。但是有时候我们希望将一些方法或属性暴露给父组件使用,这时就可以使用defineExpose。
defineProps
defineProps => 组件可以传入的参数
defineEmits
defineEmits => 组件向外暴露的自定义方法
子组件暴露方法给父组件使用,获取子组件的值
需求:无需手动点击刷新页面数据实时同步更新
实现想法一 定时器setInterval+watch
setInterval(() => {
let _that = this;
setTimeout(
function () {
_that.getlist(); //加载数据函数 自己的方法
console.log("刷新" + new Date());
}, 0);
}, 1000);
watch,它可以用来监测Vue实例上的数据变动
于是发现比较浪费性能并没有达到我想要的预期效果
实现想法二 ajax的长轮询
Ajax轮询:客户端是按照规定时间像服务端发送请求,前一次请求完成后,无论有无结果返回,规定时间之后下一次请求又会发出
Ajax长轮询:当服务端收到客户端发来的请求后,服务端不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制(服务器端设置)才返回。 客户端JavaScript响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。既把循环放到了服务端
启动类上开启异步 @EnableAsync
@RequestMapping("/async")
@RestController
public class AsyncRequestDemo {
@Autowired
private AsyncRequestService asyncRequestService;
@GetMapping("/value")
public String getValue() {
String msg = null;
Future<String> result = null;
try{
result = asyncRequestService.getValue();
msg = result.get(10, TimeUnit.SECONDS);
}catch (Exception e){
e.printStackTrace();
}finally {
if (result != null){
result.cancel(true);
}
}
return msg;
}
@PostMapping("/value")
public void postValue(String msg) {
asyncRequestService.postValue(msg);
}
}
@Service
public class AsyncRequestService {
private String msg = null;
@Async
public Future<String> getValue() throws InterruptedException {
while (true){
synchronized (this){
if (msg != null){
String resultMsg = msg;
msg = null;
return new AsyncResult(resultMsg);
}
}
Thread.sleep(100);
}
}
public synchronized void postValue(String msg) {
this.msg = msg;
}
}
这里是根据 msg 是否变化判断是否响应返回
@EnableAsync 开启异步
@Sync 标记异步方法
Future 用于接收异步返回值
result.get(10, TimeUnit.SECONDS); 阻塞,超时获取结果
Future.cancel() 中断线程
于是发现在多端中判断服务器端数据是否有更新自己发现比较困难
实现想法三 websocket
收到客户端消息后既对数据请求响应,数据的实时同步性比较好,
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
/**
* 前后端交互的类实现消息的接收推送(自己发送给自己)
*
* @ServerEndpoint(value = "/ws/one") 前端通过此URI和后端交互,建立连接
*/
@Slf4j
@ServerEndpoint(value = "/ws/one/{userid}",encoders = { EncoderClassVo.class })
@Component
public class OneWebSocket {
/**
* 与某个客户端的连接对话,需要通过它来给客户端发送消息
*/
private Session session;
/**
* 标识当前连接客户端的用户名
*/
private String userid;
/**
* 用于存所有的连接服务的客户端,这个对象存储是安全的
*/
private static ConcurrentHashMap<String,OneWebSocket> webSocketSet = new ConcurrentHashMap<>();
// websocket 不能注入( @Autowired )
private static VdataService vdataService;
@Autowired
public void setVdataService(VdataService vdataService) {
OneWebSocket.vdataService = vdataService;
}
/**
* 记录当前在线连接数
*/
// private static AtomicInteger onlineCount = new AtomicInteger(0);
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam(value = "userid")String userid) {
this.session = session;
this.userid = userid;
// userid是用来表示唯一客户端,如果需要指定发送,需要指定发送通过userid来区分
webSocketSet.put(userid,this);
// onlineCount.incrementAndGet(); // 在线数加1
log.info("有新连接加入:用户id,{},当前在线人数为:{}",this.userid, webSocketSet.size());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(Session session) {
// onlineCount.decrementAndGet(); // 在线数减1
webSocketSet.remove(this.userid);
log.info("有一连接关闭:{},用户id,{},当前在线人数为:{}", session.getId(),this.userid, webSocketSet.size());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message) throws ExecutionException, InterruptedException {
// 你的业务逻辑
JSONObject obj = JSONUtil.parseObj(message);
String userid = obj.get("userid").toString();
String page = obj.get("page").toString();
String size = obj.get("size").toString();
String isend = obj.get("isend").toString();
System.err.println(obj);
Future<Object> vData = vdataService.getlistVData(Integer.parseInt(userid), page, size, Integer.parseInt(isend));
log.info("服务端 收到 客户端 [{}]的消息:{}", userid, message);
// 你的业务逻辑
this.sendMessage(ResultDTO.success(vData.get()), userid);
}
@OnError
public void onError(Throwable error) {
webSocketSet.remove(this.userid);
log.error("发生错误");
error.printStackTrace();
}
/**
* 服务端发送消息给客户端
*/
private void sendMessage(ResultDTO message, String userid) {
System.err.println("userid "+userid);
try {
log.info("服务端 给 客户端[{}]发送消息{}", userid, JSONUtil.parseObj(message));
webSocketSet.get(userid).session.getBasicRemote().sendObject(message);
} catch (Exception e) {
log.error("服务端发送消息给客户端失败:{}", e);
}
}
}
发现服务端发送消息给客户端发送消息发送的object类型解析不了
需要配置解析类
public class EncoderClassVo implements Encoder.Text<ResultDTO>{
@Override
public void init(EndpointConfig config) {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
//如果你传递的是一个类,则使用如下写法
@Override
public String encode(ResultDTO resultDTO) throws EncodeException {
return JSONUtil.toJsonStr(resultDTO);
}
}
destroyed() {
this.websock.close() //离开路由之后断开websocket连接
},
created() {
this.initWebSocket();
},
initWebSocket(){ //初始化weosocket
console.log("初始化weosocket");
const wsuri = "ws://127.0.0.1:80/ws/one/"+this.userid;
this.websock = new WebSocket(wsuri);
this.websock.onopen = this.websocketonopen;
this.websock.onmessage = this.websocketonmessage;
this.websock.onerror = this.websocketonerror;
this.websock.onclose = this.websocketclose;
},
websocketonopen(){ //连接建立之后执行send方法发送数据
console.log("websocket-连接成功")
let data = {"hi":"发送数据"};
this.websocketsend(JSON.stringify(data));
},
websocketonerror(){//连接建立失败重连
this.initWebSocket();
},
websocketonmessage(e){ //数据接收
const redata = JSON.parse(e.data);
console.log("ws--数据接收")
this.listData = redata.data.records;
console.log(redata)
},
websocketsend(Data){//数据发送
this.websock.send(Data);
},
websocketclose(e){ //关闭
console.log('断开连接',e);
},
在有数据操作的地方只需向服务端发送消息即可 new OneWebSocket().onMessage(msg);
于是实现了自己想要的功能,以此记录
2021-02-01 10:36:08 星期一
日夜颠倒头发少 ,单纯好骗恋爱脑 ,会背九九乘法表 ,下雨只会往家跑 ,搭讪只会说你好 ---- 2050781802@qq.com