1. 实现最简单的下拉刷新雏形
<template>
<div class="wrap" ref="freshcontainer"
@touchstart="handlerstart"
@touchmove="handlermove"
@touchend="handlerend"
>
<div class="fresh_txt" v-if="moveDistance>0">释放即可刷新</div>
<slot>
</slot>
</div>
</template>
<script setup>
import { ref } from "vue";
const startLocation = ref(0);
const freshcontainer = ref(null);
const moveDistance = ref(0); //移动的位置
const isTransition = ref(false); //移动的J距离
const handlerstart = e => {
startLocation.value = e.touches[0].pageY;
};
const handlermove = e => {
moveDistance.value = Math.floor(e.touches[0].pageY - startLocation.value);
freshcontainer.value.style.transform = `translateY(${moveDistance.value}px)`;
};
const handlerend = e => {
moveDistance.value = 0;
isTransition.value = true;
freshcontainer.value.style.transform = `translateY(0px)`;
};
</script>
<style scoped>
.fresh_txt,
.load_txt {
text-align: center;
color: #ccc;
}
.ani {
transition: all 0.2s;
}
</style>
2 优化体验。当手指滑动到一定距离以后禁止再继续往下滑动,同时给手指松开的时候添加动画效果,当手指抬起时,添加文本提示加载中....增强体验感
<template>
<div :class="[{'ani':isTransition},'wrap']" ref="freshcontainer"
@touchstart="handlerstart"
@touchmove="handlermove"
@touchend="handlerend"
>
<div class="fresh_txt" v-if="moveDistance>0">释放即可刷新</div>
<div class="load_txt" v-if="loading">加载中...</div>
<slot>
</slot>
</div>
</template>
<script setup>
import { ref } from "vue";
const startLocation = ref(0);
const freshcontainer = ref(null);
const moveDistance = ref(0); //移动的位置
const loading= ref(false); //移动的位置
const isTransition = ref(false); //移动的J距离
const loading = ref(false); //移动的J距离
const handlerstart = e => {
startLocation.value = e.touches[0].pageY;
isTransition.value = false;
console.log("startLocation:", startLocation.value);
};
const handlermove = e => {
moveDistance.value = Math.floor(e.touches[0].pageY - startLocation.value);
// console.log("moveDistance.value:", moveDistance.value);
if (moveDistance.value > 100) {
moveDistance.value = 100;
}
freshcontainer.value.style.transform = `translateY(${moveDistance.value}px)`;
};
const handlerend = e => {
moveDistance.value = 0;
isTransition.value = true;
loading.value = true;
freshcontainer.value.style.transform = `translateY(0px)`;
};
</script>
<style scoped>
.fresh_txt,
.load_txt {
text-align: center;
color: #ccc;
}
.ani {
transition: all 0.2s;
}
</style>
3 把加载中的状态单独抽离出来,在父组件中用v-model去控制。
<template>
<div :class="[{'ani':isTransition},'wrap']" ref="freshcontainer"
@touchstart="handlerstart"
@touchmove="handlermove"
@touchend="handlerend"
>
<div class="fresh_txt" v-if="moveDistance>0">释放即可刷新</div>
<div class="load_txt" v-if="modelValue">加载中...</div>
<slot>
</slot>
</div>
</template>
<script setup>
import { ref } from "vue";
const startLocation = ref(0);
const freshcontainer = ref(null);
const moveDistance = ref(0); //移动的位置
const isTransition = ref(false); //移动的J距离
const loading = ref(false); //移动的J距离
const props = defineProps({
modelValue: {
type: Boolean,
default: false
}
});
const emit = defineEmits(["update:modelValue", "refresh"]);
const handlerstart = e => {
startLocation.value = e.touches[0].pageY;
isTransition.value = false;
console.log("startLocation:", startLocation.value);
};
const handlermove = e => {
moveDistance.value = Math.floor(e.touches[0].pageY - startLocation.value);
// console.log("moveDistance.value:", moveDistance.value);
if (moveDistance.value > 100) {
moveDistance.value = 100;
}
freshcontainer.value.style.transform = `translateY(${moveDistance.value}px)`;
};
const handlerend = e => {
moveDistance.value = 0;
isTransition.value = true;
freshcontainer.value.style.transform = `translateY(0px)`;
emit("update:modelValue", true);
emit("refresh");
};
</script>
<style scoped>
.fresh_txt,
.load_txt {
text-align: center;
color: #ccc;
}
.ani {
transition: all 0.2s;
}
</style>
------------------------------------------------------------------------
//父组件中的使用
<script setup>
import { ref } from "vue";
import reftest from "./components/reftest.vue";
const arr = [
{ id: "001", name: "标题一" },
{ id: "002", name: "标题二" },
{ id: "003", name: "标题三" }
];
const loading = ref(false);
const getList = () => {
setTimeout(() => {
loading.value = false;
}, 2000);
};
</script>
<template>
<reftest v-model="loading" @refresh="getList">
<div class="item" v-for="item in arr" :key="item.id">{
{item.name}}</div>
</reftest >
</template>
<style scoped>
.item {
padding: 10px 0;
border-bottom: 1px solid #ccc;
}
</style>
4 插件化,把该组件注册成一个全局组件。
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import refresh from "./components/reftest"
const app = createApp(App)
app.component("pullRefresh", refresh)
app.use(ElementPlus)
app.config.globalProperties.cons = cons
app.mount('#app')
--------------------------------------------------
//组件中使用
<script setup>
import { ref } from "vue";
const arr = [
{ id: "001", name: "标题一" },
{ id: "002", name: "标题二" },
{ id: "003", name: "标题三" }
];
const loading = ref(false);
const getList = () => {
setTimeout(() => {
loading.value = false;
}, 2000);
};
</script>
<template>
<pullRefresh v-model="loading" @refresh="getList">
<div class="item" v-for="item in arr" :key="item.id">{
{item.name}}</div>
</pullRefresh>
<!-- <GRID></GRID> -->
</template>
<style scoped>
.item {
padding: 10px 0;
border-bottom: 1px solid #ccc;
}
</style>