vue3 实现一个下拉刷新

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>

猜你喜欢

转载自blog.csdn.net/baidu_41601048/article/details/132121862
今日推荐