ele-h5项目使用vue3+vite+vant4开发:第四节、业务组件-SearchView组件开发

news2024/11/15 19:25:06

需求分析

  • 展示切换动画
  • 搜索框输入文字,自动发送请求
  • 搜索结果展示
  • 搜索状态维护
  • 历史搜索展示,点击历史搜索后发送请求
  • 历史搜索更多切换动画
  • 效果
<script setup lang="ts">
import OpSearch from '@/components/OpSearch.vue'
import { ref } from 'vue'
import { fetchSearchData } from '@/api/search'
import type { ISearchResult } from '@/types'
import { useToggle } from '@/use/useToggle'
import { computed } from 'vue'
import { watch } from 'vue'
//  声明事件接口,接口中属性值是一个函数,函数名是cancel,返回值是一个函数void
interface IEmits {
  (e: 'cancel'): void
}

const searchValue = ref('')
const searchResult = ref([] as ISearchResult[])

// 定义一个事件变量,用defineEmits方法实现,方法中引入声明的事件接口
const emits = defineEmits<IEmits>()

const HISTORY_TAGS = [
  '披萨',
  '标签2',
  '标签3',
  '标签4',
  '标签5',
  '标签6',
  '标签7',
]
const [isHistoryTagShown, toggleHistoryTag] = useToggle(false)
const historyTags = computed(() => (isHistoryTagShown.value ? HISTORY_TAGS : HISTORY_TAGS.slice(0, 5)))

// 有三种状态:搜索初始化、搜索完成、搜索中
const [INIT, DONE, DOING] = [-1, 0, 1]
const searchState = ref(INIT)

const onSearch = async (v?: string | number) => {
  console.log('onSearch', v)
  // 防止搜索状态错误
  try {
    searchState.value = DOING
    const { list } = await fetchSearchData(v as string)
    searchResult.value = list
  } finally {
    searchState.value = DONE
  }
}
const onTagClick = (v:string) => {
    searchValue.value = v
    onSearch(v)
}

watch(searchValue, (new_v) => {
    if(!new_v) {
        searchResult.value = []
        return
    }
    onSearch(new_v)
})
</script>

<template>
  <!-- 调用事件变量,传入事件名cancel // 模板代码中引入定义的事件,用来在父组件中使用对应的事件 -->
  <div class="search-view">
    <OpSearch
      show-action
      v-model="searchValue"
      shape="round"
      placeholder="请输入搜索关键词"
      @search="onSearch"
      @cancel="emits('cancel')"
    />
    <div v-if="!searchValue" class="search-view__history">
      <div class="label">历史搜索</div>

      <TransitionGroup name="list">
        <div class="history-tag" v-for="v in historyTags" :key="v" @click="onTagClick(v)">{{ v }}</div>
        <div class="history-tag" key="arrow" @click="toggleHistoryTag">
          <VanIcon v-if="isHistoryTagShown" name="arrow-up"></VanIcon>
          <VanIcon v-else name="arrow-down"></VanIcon>
        </div>
      </TransitionGroup>
    </div>
    <div v-else class="search-view__result">
      <div class="searching" v-if="searchState === DOING">~正在搜索</div>
      <template v-if="searchState === DONE">
        <div class="result-item" v-for="v in searchResult" :key="v.label">
          <VanIcon name="search"></VanIcon>
          <div class="name">{{ v.label }}</div>
          <div class="count">约{{ v.resultCount }}个结果</div>
        </div>
        <!-- 搜索结果状态维护 -->
        <div class="no-result" v-if="!searchResult.length">~暂无推荐</div>
      </template>
    </div>
  </div>
</template>

<style lang="scss">
.search-view {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  background-color: white;
  z-index: 999;
  &__history {
    padding: var(--van-padding-sm);
    .label {
      margin-bottom: var(--van-padding-xs);
    }
    .history-tag {
      display: inline-block;
      font-size: 12px;
      border-radius: 10px;
      color: var(--van-gray-6);
      background: var(--van-gray-1);
      padding: 4px 8px;
      margin-right: 10px;
      margin-bottom: var(--van-padding-xs);
    }
  }
  &__result {
    .result-item {
      display: flex;
      align-items: center;
      font-size: 12px;
      padding: 10px;
      border-radius: 1px solid var(--van-gray-1);
      .name {
        // 撑满满足padding的一行
        flex: 1;
        padding-left: 6px;
      }
      .count {
        font-size: 12px;
        color: var(--van-gray-6);
      }
    }
    .no-result, .searching {
        font-size: 12px;
        padding: 100px 0;
        text-align: center;
        color: var(--van-gray-6)
    }
  }
}

.list-enter-active,
.list-leave-active {
  transition: all 1s ease;
}
.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateY(30px);
}
</style>

使用 <transition>和 <transition-group> 实现动画效果

使用

  • <transition>组件中,你可以使用name属性来指定动画的类名,在CSS中定义类名,并为其添加过渡效果
  • <transition>



<template>

    <!-- 动画组件使用方法 -->
    <Transition name="fade">
      <SearchView v-if="isSearchViewShown" @cancel="toggleSearchView"></SearchView>
    </Transition>


</template>

<style lang="scss">
// 动画执行效果,消失效果
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.5s ease;
}
// 动画进行时状态效果
.fade-enter-from, .fade-leave-to {
  opacity: 0;
}
</style>
  • <transition-group>

  • <template>
    
       <TransitionGroup name="list">
             // 组件里内容使用了v-for,是数组形式
            <div class="history-tag" v-for="v in historyTags" :key="v" @click="onTagClick(v)">{{ v }}</div>
            <div class="history-tag" key="arrow" @click="toggleHistoryTag">
              <VanIcon v-if="isHistoryTagShown" name="arrow-up"></VanIcon>
              <VanIcon v-else name="arrow-down"></VanIcon>
            </div>
    
    
          </TransitionGroup>
    
    
    </template>
    
    <style lang="scss">
    // 定义动画css样式
    .list-enter-active,
    .list-leave-active {
      transition: all 1s ease;
    }
    .list-enter-from,
    .list-leave-to {
      opacity: 0;
      transform: translateY(30px);
    }
    
    </style>


Search 组件复用

  • 将之前章节写好的OpSearch组件复用到SearchView组件中
  • <script setup lang="ts">
    //引入组件
    import OpSearch from '@/components/OpSearch.vue'
    import { ref } from 'vue'
    
    const onSearch = async (v?: string | number) => {
      console.log('onSearch', v)
    }
    
    // 定义搜索输入框里的参数变量
    const searchValue = ref('')
    
    
    //  声明事件接口,接口中属性值是一个函数,函数名是cancel,返回值是一个函数void
    interface IEmits {
      (e: 'cancel'): void
    }
    // 定义一个事件变量,用defineEmits方法实现,方法中引入声明的事件接口
    const emits = defineEmits<IEmits>()
    
    </script>
    
    <template>
    // 使用组件
        <OpSearch
          show-action
    //对变量searchValue值进行双向绑定
          v-model="searchValue"
          shape="round"
          placeholder="请输入搜索关键词"
    // 创建onSearch方法
          @search="onSearch"
    //定义cancel事件
          @cancel="emits('cancel')"
        />
    
    </template>

 computed 计算属性

理解

  • 方便地计算和监听数据的变化。
<script setup lang="ts">
import { useToggle } from '@/use/useToggle'
import { computed } from 'vue'

const HISTORY_TAGS = [
  '披萨',
  '标签2',
  '标签3',
  '标签4',
  '标签5',
  '标签6',
  '标签7',
]
const [isHistoryTagShown, toggleHistoryTag] = useToggle(false)

const historyTags = computed(() => (isHistoryTagShown.value ? HISTORY_TAGS : HISTORY_TAGS.slice(0, 5)))


<template>

        <div class="history-tag" key="arrow" @click="toggleHistoryTag">

          <VanIcon v-if="isHistoryTagShown" name="arrow-up"></VanIcon>
          <VanIcon v-else name="arrow-down"></VanIcon>

        </div>

</template>

watch 监听属性

理解

  • watch函数接受两个参数:一个是要监听的参数,以及一个回调函数。回调函数触发的前提是,当被监听的参数发生变化时,回调函数将被执行。
  • <script setup lang="ts">
    // 引入watch函数
    import { watch } from 'vue'
    
    // watch监听函数的使用方法,监听searchValue参数又叫属性值的变化,有变动时就会触发回调函数中的代码。
    watch(searchValue, (new_v) => {
        if(!new_v) {
            searchResult.value = []
            return
        }
        onSearch(new_v)
    })
    
    </script>

使用
axios实例发送业务请求

  • 开发环境配置反向代理使用服务接口
  • 设置请求响应拦截
  • 创建具体功能请求函数
  • 调用功能请求函数


mock 请求:

看这篇文章 使用apifox创建一个Mock Server Api 接口-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1431209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

React Hooks 学习笔记

1.useState&#xff08;&#xff09; 实现对页面数据的存储&#xff0c;当数据改变时候&#xff0c;自动触发render函数 2.useRef 用来解决两个问题&#xff1a; 1).是获取DOM元素或子组件的实例对象 2).存储渲染周期之间共享的数据 3.useEffect 4.useLayoutEffect 5…

IDEA 配置以及一些技巧

1. IDEA设置 1.1 设置主题 1.2 设置字体和字体大小 1.3 编辑区的字体用ctrl鼠标滚轮可以控制大小 1.4 自动导包和优化多余的包 1.5 设置编码方式 1.6 配置 maven 1.7 设置方法形参参数提示 1.8 设置控制台的字体和大小 注意&#xff1a;设置控制台字体和大小后需要重启IDEA才会…

90.网游逆向分析与插件开发-游戏窗口化助手-项目需求与需求拆解

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;实现物品使用策略的功能-CSDN博客 项目需求&#xff1a; 在游戏窗口化时&#xff0c;可以在游戏之外弹出一个窗口&#xff0c;可以隐藏或者显示游戏窗口&#xff0c;显示游戏人物的基本状态&#xff…

【Springcloud篇】学习笔记九(十五、十六章):Cloud Alibaba介绍、Nacos服务注册、服务配置中心

第十五章_Cloud Alibaba简介 1.出现SpringCloud Alibaba的原因 SpringCloud Netflix项目进入维护模式 技术的发展 2.SpringCloud Alibaba简介 2.1是什么 2.2能干嘛 2.3去哪下 阿里巴巴中文文档下载网站&#xff1a; spring-cloud-alibaba/README-zh.md at 2022.x alibaba…

js获取文件名或文件后缀名(扩展名)的几种方法

有时候我们需要通过含有文件名和后缀名的一个字符串中提取出该文件的文件名或文件后缀名&#xff08;扩展名&#xff09;&#xff0c;可以通过如下几种方式进行截取。 例如文件名为: var fileName"12345.txt"; 方式一&#xff1a;subtring() 用法参考博文 【js截取字…

深度学习驱动下的自然语言处理进展及其应用前景

文章目录 每日一句正能量前言技术进步应用场景挑战与前景自然语言处理技术当前面临的挑战未来的发展趋势和前景 伦理和社会影响实践经验后记 每日一句正能量 一个人若想拥有聪明才智&#xff0c;便需要不断地学习积累。 前言 自然语言处理&#xff08;NLP&#xff09;是一项正…

查看自己电脑是arm还是x64(x86);linux操作系统识别

1、查看自己电脑是arm还是x64&#xff08;x86&#xff09; linux 参考&#xff1a; https://liuweiqing.blog.csdn.net/article/details/131783851 uname -a如果输出是 x86_64&#xff0c;那么你的系统是 64 位的 x86 架构&#xff08;通常我们称之为 x64&#xff09;。如果…

Jmeter 基于Docker 实现分布式测试

基于Docker 实现分布式测试 制作Jmeter基础镜像制作工作节点镜像启动工作节点启动控制节点遇到的问题 使用Docker 部署Jmeter非常方便&#xff0c;可以省略软件的安装以及配置&#xff0c;比如jdk、jmeter。需要部署多个工作节点可以节省时间。 控制节点&#xff08;Master-主节…

nodejs+vue+ElementU教师科研管理系统l33wm

本次开发一套高校教师科研管理系统有管理员&#xff0c;教师&#xff0c;学院三个角色。管理员功能有个人中心&#xff0c;教师管理&#xff0c;学院管理&#xff0c;科研课题管理&#xff0c;软件著作权管理&#xff0c;论文信息管理&#xff0c;专利信息管理&#xff0c;科研…

QXlsx Qt操作excel(1)

QXlsx 是一个用于处理Excel文件的开源C库。它允许你在你的C应用程序中读取和写入Microsoft Excel文件&#xff08;.xlsx格式&#xff09;。该库支持多种操作&#xff0c;包括创建新的工作簿、读取和写入单元格数据、格式化单元格、以及其他与Excel文件相关的功能。 关于QXlsx的…

[office] 在Excel2010中设定某些单元格数据不参与排序的方法介绍 #其他#知识分享#笔记

在Excel2010中设定某些单元格数据不参与排序的方法介绍 在Excel中排序&#xff0c;相信大家都会了&#xff0c;直接将一组数据按照从小到大或者从大到小进行排序&#xff0c;但是&#xff0c;现在要求我们规定其中几组数据不进行排序&#xff0c;只排序其余的部分。又该如何操作…

电源模块欠压保护点测试方法分享 纳米软件

电源欠压保护原理 欠压保护是指当电源电压低于一定值时&#xff0c;电源的保护功能会及时断开电路&#xff0c;避免设备受到损坏。电源欠压保护一般是通过一个或多个传感器来检测电压&#xff0c;当电压低于设定值时就会触发电源的保护功能&#xff0c;断开电路&#xff0c;保护…

树莓派-Ubuntu22.04

树莓派 1 安装Ubuntu系统2 ssh登录3 配置3.1 安装软件3.2 换源3.3 安装桌面3.4 开机脚本 1 安装Ubuntu系统 通过制作sdk&#xff0c;使系统在sdk中运行&#xff1a; 下载制作软件&#xff1a;https://www.raspberrypi.com/software/ 下载Ubuntu镜像&#xff1a;https://cn.ub…

Spring事件之注解@EventListener讲解

文章目录 1 注解EventListener1.1 示例Demo1.1.1 简单例子1.1.2 解耦1.1.3 Spring事件 1.2 深入EventListener1.2.1 debug调试1.2.2 问题一&#xff1a; Spring是怎么知道要去触发这个方法1.2.3 问题二&#xff1a;ApplicationListenerMethodAdapter1.2.4 问题三&#xff1a;Si…

(Python)列表字典数据本地存储工具

一个简单的实现简便 "列表字典" 数据存储本地。 适合不会SQL但又想实现数据存储本地的同学。 操作使用都非常简单。 文件只做了简单的加密处理&#xff0c;如果需要复杂加密的同学可以修改加密函数。 感兴趣并且动手能力强的同学&#xff0c;可以把它封装成工具类…

Linux Centos stream9 mdadm

RAID(Redundant Array of Independent Disk独立冗余磁盘阵列)技术是加州大学伯克利分校1987年提出&#xff0c;最初是为了组合小的廉价磁盘来代替大的昂贵磁盘&#xff0c;同时希望磁盘失效时不会使对数据的访问受损失而开发出一定水平的数据保护技术。RAID就是一种由多块廉价磁…

Fink CDC数据同步(二)MySQL数据同步

1 开启binlog日志 2 数据准备 use bigdata; drop table if exists user;CREATE TABLE user(id INTEGER NOT NULL AUTO_INCREMENT,name VARCHAR(20) NOT NULL DEFAULT ,birth VARCHAR(20) NOT NULL DEFAULT ,gender VARCHAR(10) NOT NULL DEFAULT ,PRIMARY KEY(id) ); ALTER TA…

vite打包原理

vite 工程化开发&#xff1a;打包工具 启动速度很快 核心原理还是webpack 把webpack封装了&#xff0c;把webpack对象封装了 和vue2整体结构几乎一致 webpack两种模式&#xff1a;开发&生产 代码打包编译&#xff0c;本地起一个web服务器实时预览编译后的结果 build 命令模…

Spark 开启动态资源分配

一 为什么要开启动态资源分配 ⽤户提交Spark应⽤到Yarn上时&#xff0c;可以通过spark-submit的num-executors参数显示地指定executor个数&#xff0c;随后&#xff0c; ApplicationMaster会为这些executor申请资源&#xff0c;每个executor作为⼀个Container在Yarn上运⾏。 S…

【数据结构】并查集(路径压缩)

文章目录 并查集1.朴素版本2.路径压缩3.按秩合并4.启发式合并5.练习题 并查集 1.朴素版本 1. 并查集解决的是连通块的问题&#xff0c;常见操作有&#xff0c;判断两个元素是否在同一个连通块当中&#xff0c;两个非同一连通块的元素合并到一个连通块当中。 并查集和堆的结构…