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

需求分析

  • 展示切换动画
  • 搜索框输入文字,自动发送请求
  • 搜索结果展示
  • 搜索状态维护
  • 历史搜索展示,点击历史搜索后发送请求
  • 历史搜索更多切换动画
  • 效果
<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博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Jenkins(本地Windows上搭建)上传 Pipeline构建前端项目并将生成dist文件夹上传至指定服务器

下载安装jdk https://www.oracle.com/cn/java/technologies/downloads/#jdk21-windows 下载jenkins window版 双击安装 https://www.jenkins.io/download/thank-you-downloading-windows-installer-stable/ 网页输入 http://localhost:8088/ 输入密码、设置账号、安装推…

Ainx框架实现 一

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于Ainx系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基础系列…

Mysql+MybatisPlus+Vue实现基础增删改查CRUD

数据库 设计数据库 设计几个字段&#xff0c;主键id自动增长且不可为空 create table if not exists user (id bigint(20) primary key auto_increment comment 主键id,username varchar(255) not null comment 用户名,sex char(1) not null comment 性…

C++弹球游戏:Jump Ball Game

一、下载压缩包 请查看网站C弹球游戏&#xff1a;Jump Ball Game并且下载&#xff0c;可以看到如下界面&#xff1a; 二、匹配图标 把压缩包解压了&#xff1a; 右键点击Jump Ball Game.lnk&#xff0c;点击“属性”它将会是我们要运行的文件。 点击“更改图标”&#xff0c;选…

【HarmonyOS 4.0 应用开发实战】ArkTS 快速入门

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

344. Reverse String(反转字符串)

题目描述 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 问题分析 以中间字符为轴&#xff0c;将两边的字符对换…

Python 轻量级定时任务调度:APScheduler

简述 APscheduler (Advanced Python Scheduler)&#xff0c;作用为按指定的时间规则执行指定的作业。提供了基于日期date、固定时间间隔interval 、以及类似于Linux上的定时任务crontab类型的定时任务。该框架不仅可以添加、删除定时任务&#xff0c;还可以将任务存储到数据库…

浅谈Zookeeper及windows下详细安装步骤

1. Zookeeper介绍 1.1 分布式系统面临的问题 分布式系统是一个硬件或软件组件分布在不同的网络计算机上&#xff0c;彼此之间仅仅通过消息传递进行通信和协调的系统。 面临的问题&#xff1a;系统每个节点之间信息同步及共享 以一个小团队为例,面临的问题 通过网络进行信息…

蓝桥杯---生日蜡烛

某君从某年开始每年都举办一次生日party&#xff0c;并且每次都要吹熄与年龄相同根数的蜡烛&#xff0c;现在算起来&#xff0c;他一共吹熄了236根蜡烛。请问,他从多少岁开始过生日party的? 请填写他开始过生日 party的年龄数。 注意:你提交的应该是一个整数&#xff0c;不要…

二分查找第二弹

目录 力扣852.山脉数组的峰顶索引 力扣162.寻找峰值 力扣153.寻找旋转排序数组中的最小值 力扣剑指Offer53.0-n-1缺失的数字 力扣852.山脉数组的峰顶索引 峰顶之前的全部比他小&#xff0c;峰顶之后的也比他小&#xff0c;把小于等于和大于分成两段 class Solution {publi…

TQ15EG开发板教程:使用vivado2023.1建立hello world工程

1:打开软件建立工程 2:使用vivado创建设计模块并生成bit文件 3:导出硬件平台&#xff0c;使用vitis建立工程 4:使用vitis创建应用程序项目 5:硬件设置与调试 1:打开软件建立工程 打开VIVADO2023.1 创建一个新的工程 输入项目名称和地址&#xff0c;下面那个选项为是否…

深入了解关联查询和子查询

推荐阅读 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;一&#xff09; 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;二&#xff09; 文章目录 推荐阅读关联查询子查询 关联查询 关联查询 从多张表中查询对应记录的信息&#xff0c;关联查…

网络原理-TCP/IP(5)

TCP协议 延迟应答 它也是基于滑动窗口,提高效率的一种机制,结合滑动窗口以及流量控制,能够以延迟应答ACK的方式,把反馈的窗口,搞大.核心在于允许范围内,让窗口尽可能大. 如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小. 1.假设接收端缓冲区为1M.一次收到了5…

Java特别篇--关于线程创建的三种方式的总结对比

文章目录 一、常见3种创建线程的方式&#xff08;1&#xff09;方式1&#xff1a;继承Thread类的方式&#xff08;2&#xff09;方式2&#xff1a;实现Runnable接口的方式&#xff08;3&#xff09;方式3&#xff1a;通过Callable和Future接口创建线程 二、对比三种方式&#x…

CUDA/TensorRT部署知识点

CUDA相关: 1、CUDA核函数嵌套核函数的用法多吗? 答:这种用法非常少,主要是因为启动一个kernel本身就有一定延迟,会造成执行的不连续性。 2、如下代码里的 grid/block 对应硬件上的 SM 的关系是什么? 答:首先需要理解grid/block是软件层的概念,而SM是硬件层的概念。所…

python脚本将照片按时间线整理

说明&#xff1a;有一次自己瞎折腾&#xff0c;然后把服务器相册搞崩了&#xff0c;后来做了备份同步给找了回来&#xff0c;但是相册的时间线全乱了&#xff0c;看起来非常难受。所以就想通过文件夹的形式把照片重新分类&#xff0c;分类后的结构如下(红色字体为文件夹)&#…

人生百相,不过熵增熵减

这篇博文由两个问题衍生而来&#xff0c;分别是&#xff1a;“为什么除法比加法困难”、“什么是生命进化的目的”。在阅读其他人的解读时&#xff0c;发现都关联到了一个概念&#xff0c;熵。觉得十分有意思&#xff0c;因此记录一下自己的遐想。 熵&#xff08;Entropy&#…

vulhub中spring的CVE-2022-22965漏洞复现

在JDK 9上运行的Spring MVC或Spring WebFlux应用程序可能存在通过数据绑定执行远程代码&#xff08;RCE&#xff09;的漏洞。 现在已知的利用方法要求应用程序以WAR部署的形式在Tomcat上运行&#xff0c;然而&#xff0c;该漏洞的性质更为普遍&#xff0c;可能有其他方法可以利…

docker安装-centos

Docker CE 支持 64 位版本 CentOS 7&#xff0c;并且要求内核版本不低于 3.10 卸载旧版本Docker sudo yum remove docker \ docker-common \ docker-selinux \ docker-engine使用yum安装 yum 更新到最新版本: sudo yum update执行以下命令安装依赖包&#xff1a; sudo yum…

【无刷电机】无感方波驱动方案

无感方波驱动方案 1.通过无感过零信号构造霍尔换相信号2.无刷硬件驱动方案3.无感方波控制程序框架3.1有感方波控制3.2无感方波控制3.3无感启动方案3.4无感速度闭环控制1.通过无感过零信号构造霍尔换相信号 实现无感方波控制有软件比较和硬件比较两种方案。 软件比较是通过ADC采…