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>