ele-h5项目使用vue3+vite开发:第二节、search 搜索框组件开发

news/2024/7/7 22:12:51

如何设计一个组件

 需求分析

 布局

  • content
    • left-icon
    • body
    • input-control
    • right-icon
  • action

功能

使用 defineEmits 定义组件的事件

在组件的script setup 里如何定义事件

  • 使用defineEmits()定义
  • 先声明事件接口
  • <script setup lang="ts">
    interface IProps {
      showAction?: boolean
      background?: string
      placeholder?: string
      shape?: string
      modelValue?: string | number
    }
    
    const props = defineProps<IProps>()
    
    // 声明事件接口
    interface IEmits {
      (e: 'search', v?: string | number): void
      (e: 'cancel'): void
      (e: 'clear'): void
      (e: 'update:modelValue', v?: string | number): void
    }
    
    // 定义事件变量
    const emits = defineEmits<IEmits>()
    
    const onKeyPress = (e: KeyboardEvent) => {
      const ENTER_CODE = 13
      if (ENTER_CODE === e.keyCode) {
        e.preventDefault()
    //使用定义事件里声明事件接口中的某个事件
        emits('search', props.modelValue)
      }
    }
    
    const onClear = () => {
    //使用定义事件里声明事件接口中的某个事件
      emits('clear')
    //使用定义事件里声明事件接口中的某个事件
      emits('update:modelValue', '')
    }
    </script>
    
    <template>
      <div class="op-search" :class="{ 'op-search--show-action': showAction }" :style="{ background }">
        <div class="op-search__content" :class="shape ? `op-search__content--${shape}` : ''">
          <div class="op-cell op-search__field">
            <div class="op-field__left-icon">
              <VanIcon name="search" />
            </div>
            <div class="op-cell__value">
              <div class="op-field__body">
                <input
                  type="search"
                  class="op-field__control"
                  :value="modelValue"
                  :placeholder="placeholder"
                  @keypress="onKeyPress"
    
                //使用定义事件里声明事件接口中的某个事件, 以及传递input输入框里的值
                  @input="(e) => emits('update:modelValue', (e.target as HTMLInputElement).value)"
                />
                <div v-if="$slots['right-icon']" class="op-field__right-icon">
                  <slot name="right-icon"></slot>
                </div>
                <VanIcon
                  v-else-if="modelValue"
                  name="clear"
                  class="op-field__clear-icon"
    //使用定义的函数事件,触发里面的定义事件里声明事件接口中的某个事件
                  @click="onClear"
                />
              </div>
            </div>
          </div>
        </div>
        <div v-if="showAction" class="op-search__action">
          <slot name="action">
    //定义事件里声明事件接口中的某个事件
            <div @click="emits('cancel')">取消</div>
          </slot>
        </div>
      </div>
    </template>

如何定义组件的 v-model

在组件的script setup 里如何定义 v-model 参数

  • 声明接口属性,定义v-model双向绑定的变量参数。
  • 使用定义的v-model双向绑定的变量参数
  • <script setup lang="ts">
    
    //声明变量参数的接口属性
    interface IProps {
      showAction?: boolean
      background?: string
      placeholder?: string
      shape?: string
      modelValue?: string | number
    }
    
    // 定义v-model双向绑定使用的变量参数
    const props = defineProps<IProps>()
    
    interface IEmits {
      (e: 'search', v?: string | number): void
      (e: 'cancel'): void
      (e: 'clear'): void
      (e: 'update:modelValue', v?: string | number): void
    }
    
    const emits = defineEmits<IEmits>()
    
    const onKeyPress = (e: KeyboardEvent) => {
      const ENTER_CODE = 13
      if (ENTER_CODE === e.keyCode) {
        e.preventDefault()
    
    //在script setup中使用定义v-model双向绑定使用的变量参数
        emits('search', props.modelValue)
      }
    }
    
    const onClear = () => {
      emits('clear')
      emits('update:modelValue', '')
    }
    </script>
    
    <template>
    //在template中使用定义v-model双向绑定使用的变量参数 showAction background shape
      <div class="op-search" :class="{ 'op-search--show-action': showAction }" :style="{ background }">
        <div class="op-search__content" :class="shape ? `op-search__content--${shape}` : ''">
          <div class="op-cell op-search__field">
            <div class="op-field__left-icon">
              <VanIcon name="search" />
            </div>
            <div class="op-cell__value">
              <div class="op-field__body">
    //在template中使用定义v-model双向绑定使用的变量参数 modelValue placeholder
                <input
                  type="search"
                  class="op-field__control"
                  :value="modelValue"
                  :placeholder="placeholder"
                  @keypress="onKeyPress"
                  @input="(e) => emits('update:modelValue', (e.target as HTMLInputElement).value)"
                />
                <div v-if="$slots['right-icon']" class="op-field__right-icon">
                  <slot name="right-icon"></slot>
                </div>
    //在template中使用定义v-model双向绑定使用的变量参数 modelValue 
    
                <VanIcon
                  v-else-if="modelValue"
                  name="clear"
                  class="op-field__clear-icon"
                  @click="onClear"
                />
              </div>
            </div>
          </div>
        </div>
    //在template中使用定义v-model双向绑定使用的变量参数 showAction
    
        <div v-if="showAction" class="op-search__action">
          <slot name="action">
            <div @click="emits('cancel')">取消</div>
          </slot>
        </div>
      </div>
    </template>
    

是的

如何使用 CSS 变量

定义css变量,使用var(--van-padding-xs)格式来书写vue3的css变量,可以在script setup中进行自定义css变量值

  • 在组件中使用css变量
  • 
    <template>
      <div class="op-search" :class="{ 'op-search--show-action': showAction }" :style="{ background }">
        <div class="op-search__content" :class="shape ? `op-search__content--${shape}` : ''">
          <div class="op-cell op-search__field">
            <div class="op-field__left-icon">
              <VanIcon name="search" />
            </div>
            <div class="op-cell__value">
              <div class="op-field__body">
                <input
                  type="search"
                  class="op-field__control"
                  :value="modelValue"
                  :placeholder="placeholder"
                  @keypress="onKeyPress"
                  @input="(e) => emits('update:modelValue', (e.target as HTMLInputElement).value)"
                />
                <div v-if="$slots['right-icon']" class="op-field__right-icon">
                  <slot name="right-icon"></slot>
                </div>
                <VanIcon
                  v-else-if="modelValue"
                  name="clear"
                  class="op-field__clear-icon"
                  @click="onClear"
                />
              </div>
            </div>
          </div>
        </div>
        <div v-if="showAction" class="op-search__action">
          <slot name="action">
            <div @click="emits('cancel')">取消</div>
          </slot>
        </div>
      </div>
    </template>
    
    <style lang="scss">
    :root {
    
    
    // 定义css变量var(变量格式),可以让引用组件的父组件自定义css值
    
    
      --op-search-padding: 10px var(--van-padding-sm);
      --op-search-background-color: var(--van-background-color-light);
      --op-search-content-background: var(--van-gray-1);
      --op-search-left-icon-color: var(--van-gray-6);
      --op-search-action-padding: 0 var(--van-padding-xs);
      --op-search-action-text-color: var(--van-text-color);
      --op-search-action-font-size: var(--van-font-size-md);
      --op-search-input-height: 34px;
    }
    
    .op-search {
      display: flex;
      align-items: center;
      box-sizing: border-box;
      padding: var(--op-search-padding);
      background: var(--op-search-background-color);
    
      &--show-action {
        padding-right: 0;
      }
    
      &__content {
        display: flex;
        flex: 1;
        padding-left: var(--van-padding-sm);
        background: var(--op-search-content-background);
        border-radius: var(--van-border-radius-sm);
        &--round {
          border-radius: var(--van-radius-max);
        }
      }
    
      &__action {
        padding: var(--op-search-action-padding);
        color: var(--op-search-action-text-color);
        font-size: var(--op-search-action-font-size);
        line-height: var(--op-search-input-height);
        cursor: pointer;
        user-select: none;
      }
    
      &__field {
        flex: 1;
        padding: 5px var(--van-padding-xs) 5px 0;
        background-color: transparent;
    
        .op-field__left-icon {
          color: var(--op-search-left-icon-color);
          margin-right: var(--van-padding-base);
          .van-icon {
            font-size: var(--van-field-icon-size);
          }
        }
      }
    }
    
    .op-cell {
      display: flex;
      box-sizing: border-box;
      width: 100%;
      color: var(--van-cell-text-color);
      font-size: var(--van-cell-font-size);
      line-height: var(--van-cell-line-height);
      &__value {
        flex: 1;
        color: var(--van-cell-text-color);
        vertical-align: middle;
        word-wrap: break-word;
      }
    }
    
    .op-field {
      &__control {
        display: block;
        box-sizing: border-box;
        width: 100%;
        min-width: 0;
        margin: 0;
        padding: 0;
        border: 0;
        color: var(--van-field-input-text-color);
        line-height: inherit;
        text-align: left;
        background-color: transparent;
        resize: none;
        user-select: none;
        &::placeholder {
          color: var(--van-field-placeholder-text-color);
        }
      }
      &__body {
        display: flex;
        align-items: center;
      }
      &__right-icon {
        color: var(--van-field-right-icon-color);
        padding: 0 var(--van-padding-xs);
        line-height: inherit;
        flex-shrink: 0;
      }
      &__clear {
        color: var(--van-field-clear-icon-color);
        font-size: var(--van-field-clear-icon-size) !important;
        cursor: pointer;
      }
    }
    input {
      &::-webkit-search-decoration,
      &::-webkit-search-cancel-button,
      &::-webkit-search-results-button,
      &::-webkit-search-results-decoration {
        display: none;
      }
    }
    </style>
    

BEM 命名规范

定义

  • Bem是块(block) 、元素(element) 、修饰符(modifier)的简写
  • - 中划线:仅作为连字符使用,表示某个块或者某个子元素的多单词之间的连接记号
  • __ 双下划线:双下划线用来连接块和块的子元素
  • -- 双中划线:双中划线用来描述一个块或者块的子元素的一种状态

http://lihuaxi.xjx100.cn/news/2006426.html

相关文章

【蓝桥备赛】优先队列

优先队列 队列是基于数组或者链表来实现的&#xff0c;是线性的结构&#xff1b;队列的特点是先进先出。 优先队列是一种特殊类型的队列&#xff0c;其中元素被赋予优先级&#xff0c;具有较高优先级的元素先被处理。 在竞赛中经常会遇到优先队列的思想 基本语法 基本语法…

python封装的.exe文件是如何在cmd中获取.xml路径的?

这段日子搞项目算法封装&#xff0c;愁死我。来回改了三遍&#xff0c;总算把相对路径、绝对路径&#xff0c;还有cmd给.exe传参的方式搞懂了。 主要是这个语句 workspace sys.argv[1] sys.argv[]的作用就是,在运行python文件的时候从外部输入参数往文件里面传递参数。 外部就…

linux+rv1126/imx6ull:opencv静态库交叉编译

目录 1.下载 2.准备工作 2.1安装依赖环境 2.2安装Cmake 2.3 解压opencv 3.Cmake设置 3.1文件夹选择 1&#xff09;进入源码根目录 2&#xff09;运行cmake 3&#xff09;选择目录 4&#xff09;进入配置界面 5&#xff09;查找编译器 6&#xff09;配置编译器 3.…

TCP 连接掉线自动重连

文章目录 TCP 连接掉线自动重连定义使用连接效果 TCP 接收数据时防止掉线。TCP 连接掉线自动重连。多线程环境下TCP掉线自动重连。 欢迎讨论更好的方法&#xff01; TCP 连接掉线自动重连 定义 定义一个类&#xff0c;以编写TCP连接函数Connect()&#xff0c;并且&#xff1a…

python实现的LDA算法

实现LDA算法需要用到一些数学和概率统计的知识&#xff0c;你需要根据LDA算法的具体公式&#xff0c;实现初始化模型参数、Gibbs采样、模型参数更新等具体的步骤。同时&#xff0c;还需要读取训练文件和词典文件&#xff0c;以及保存模型到文件的功能。 理解LDA算法的实现思路…

2024年美赛C题:Momentum in Tennis思路解析

Problem C: Momentum in Tennis 网球运动中的动力 【扫描下方二维码加入群聊&#xff0c;了解更多思路~】 中文题目&#xff1a; 在2023年温布尔登男子单打决赛中&#xff0c;20岁的西班牙新星卡洛斯阿尔卡拉斯击败了36岁的诺瓦克德约科维奇。这是德约科维奇自2013年以来在温布…

Leetcode刷题150. 逆波兰表达式求值

给你一个字符串数组 tokens &#xff0c;表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意&#xff1a; 有效的算符为 、-、* 和 / 。每个操作数&#xff08;运算对象&#xff09;都可以是一个整数或者另一个表达式。两个…

时空数据挖掘新思路!25篇顶会论文汇总,含2024最新!

在科技飞速发展的今天&#xff0c;我们正处在一个大数据无处不在的时代&#xff0c;在这个时代背景下&#xff0c;时空数据变得尤为重要&#xff0c;它不仅记录了事物的位置和时间变化&#xff0c;还揭示了地理实体间的复杂联系和动态模式。 为了充分挖掘这些数据的潜在价值&am…