Vue.js 2 项目实战(九):商品列表

news2024/11/18 1:36:59

前言

Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它的设计初衷是通过采用简洁且强大的结构,使前端开发变得更简单和高效。以下是对 Vue.js 的详细介绍:

核心特性

  1. 声明式渲染

    • Vue.js 使用声明式语法来描述用户界面,通过数据绑定实现视图的自动更新。
  2. 组件系统

    • Vue.js 提供了一个灵活的组件系统,可以将 UI 拆分为可复用的独立组件,每个组件包含自己的模板、逻辑和样式。
  3. 单文件组件 (SFC)

    • Vue.js 允许将 HTML、CSS 和 JavaScript 放在一个 .vue 文件中,这种单文件组件的结构使得组件开发更加直观和模块化。
  4. 虚拟 DOM

    • Vue.js 使用虚拟 DOM 来优化视图更新,通过最小化实际 DOM 操作,提高性能。
  5. 反应式数据绑定

    • Vue.js 提供了响应式的数据绑定系统,当数据变化时,视图会自动更新。
  6. 指令

    • Vue.js 提供了一组内置指令,如 v-bindv-modelv-for,可以轻松操作 DOM。

优点

  1. 易于上手

    • Vue.js 的学习曲线较低,适合新手入门,并且有详细的文档和教程。
  2. 灵活性

    • Vue.js 可以逐步采用,可以用于小部分的功能增强,也可以用于构建复杂的单页面应用(SPA)。
  3. 高性能

    • 虚拟 DOM 和响应式系统使得 Vue.js 在处理数据密集型操作时表现优异。
  4. 强大的生态系统

    • Vue.js 生态系统丰富,包括 Vue Router、Vuex、Vue CLI 等,提供了强大的开发工具支持。
  5. 活跃的社区

    • Vue.js 拥有一个活跃的社区,有大量的插件、教程和支持资源。

知识点

// my-tag 标签组件的封装
// 1. 创建组件 - 初始化
// import 语句用于导入其他文件或模块
import MyTag from "./components/MyTag.vue";

// export default 是 ES6 模块的导出语法,表示将对象作为模块的默认导出。这里导出的是一个对象,它定义了 Vue 组件的选项
export default {
  // name: 'TableCase' 定义了组件的名称
  name: 'TableCase',
  // components 是一个对象,用于注册子组件
  components: {
    MyTag
  }

// 2. 实现功能
//    (1) 双击显示,并且自动聚焦
//      v-if v-else @dblclick(双击) 操作 isEdit 自动聚焦:
//      $nextTick =>$refs 获取到dom,进行 focus 获取焦点
//      封装 v-focus 指令在 main.js
//    (2) 失去焦点,隐藏输入框
//      @blur(失去焦点) 操作 isEdit 即可
//    (3) 回显标签信息
//      回显的标签信息是父组件传递过来的
//      v-model 实现功能(简化代码) v-model=>:value 和 @input 组件内部通过 props 接收
//      :value 设置给输入框内容修改了
//    (4) 内容修改了,回车 => 修改标签信息
//      @keyup.enter,触发事件 $emit('input',e.target.value)


// 1.my-tag 标签组件封装
// (1)双击显示输入框,输入框获取焦点
// (2)失去焦点,隐藏输入框
// (3)回显标签信息
// (4)内容修改,回车→修改标签信息

// 2.my-table 表格组件封装
// (1)动态传递表格数据渲染
// (2)表头支持用户自定义
// (3)主体支持用户自定义

项目效果

源代码

App.vue

<template>
  <div class="table-case">
    <MyTable :data="goods">
      <!-- 使用 <template #head> 来指定插入到子组件 head 插槽的内容 -->
      <template #head>
        <th>编号</th>
        <th>图片</th>
        <th>名称</th>
        <th>标签</th>
      </template>
      <!-- slotProps:这是一个插槽属性对象,包含了父组件通过插槽传递给子组件的数据 -->
      <template #body="slotProps">
        <td>{{ slotProps.index + 1 }}</td>
        <td><img :src="slotProps.item.picture"  alt="#"/></td>
        <td>{{ slotProps.item.name }}</td>
        <td>
          <!-- 父传子 -->
          <MyTag v-model="slotProps.item.tag"></MyTag>
        </td>
      </template>
    </MyTable>

  </div>
</template>

<script>
// my-tag 标签组件的封装
// 1. 创建组件 - 初始化
// 2. 实现功能
//    (1) 双击显示,并且自动聚焦
//      v-if v-else @dblclick(双击) 操作 isEdit 自动聚焦:
//      $nextTick =>$refs 获取到dom,进行 focus 获取焦点
//      封装 v-focus 指令在 main.js
//    (2) 失去焦点,隐藏输入框
//      @blur(失去焦点) 操作 isEdit 即可
//    (3) 回显标签信息
//      回显的标签信息是父组件传递过来的
//      v-model 实现功能(简化代码) v-model=>:value 和 @input 组件内部通过 props 接收
//      :value 设置给输入框内容修改了
//    (4) 内容修改了,回车 => 修改标签信息
//      @keyup.enter,触发事件 $emit('input',e.target.value)

// 1.my-tag 标签组件封装
// (1)双击显示输入框,输入框获取焦点
// (2)失去焦点,隐藏输入框
// (3)回显标签信息
// (4)内容修改,回车→修改标签信息

// 2.my-table 表格组件封装
// (1)动态传递表格数据渲染
// (2)表头支持用户自定义
// (3)主体支持用户自定义

// import 语句用于导入其他文件或模块
// import MyTag from "./components/MyTag.vue";
import MyTable from "@/components/MyTable.vue";
import MyTag from "@/components/MyTag.vue";

// export default 是 ES6 模块的导出语法,表示将对象作为模块的默认导出。这里导出的是一个对象,它定义了 Vue 组件的选项
export default {
  // name: 'TableCase' 定义了组件的名称
  name: 'TableCase',
  // components 是一个对象,用于注册子组件
  components: {
    MyTag,
    MyTable
  },
  data () {
    return {
      // 测试功能临时数据
      tempText: '茶壶',
      tempText2: '无敌',
      goods: [
        { id: 101, picture: 'https://yanxuan-item.nosdn.127.net/f8c37ffa41ab1eb84bff499e1f6acfc7.jpg', name: '梨皮朱泥三绝清代小品壶经典款紫砂壶', tag: '茶具' },
        { id: 102, picture: 'https://yanxuan-item.nosdn.127.net/221317c85274a188174352474b859d7b.jpg', name: '全防水HABU旋钮牛皮户外徒步鞋山宁泰抗菌', tag: '男鞋' },
        { id: 103, picture: 'https://yanxuan-item.nosdn.127.net/cd4b840751ef4f7505c85004f0bebcb5.png', name: '毛茸茸小熊出没,儿童羊羔绒背心73-90cm', tag: '儿童服饰' },
        { id: 104, picture: 'https://yanxuan-item.nosdn.127.net/56eb25a38d7a630e76a608a9360eec6b.jpg', name: '基础百搭,儿童套头针织毛衣1-9岁', tag: '儿童服饰' },
      ]
    }
  }
}
</script>

<style lang="less" scoped>

</style>

MyTable.vue

<script>
export default ({
  props: {
    data: {
      type: Array,
      required: true
    }
  }
})
</script>

<template>
  <table class="my-table">
    <thead>
    <tr>
      <!-- <slot> 是一种用于组件内容分发的机制,允许你将内容从父组件传递到子组件 -->
      <!-- <slot> 元素被称为插槽(slot),它定义了子组件中可以插入内容的位置 -->
      <!-- name="head":这是一个可选的属性,用于为插槽指定一个名称。通过名称,你可以在父组件中指定哪些内容应该插入到这个插槽中 -->
      <slot name="head"></slot>
    </tr>
    </thead>
    <tbody>
    <tr v-for="(item, index) in data" :key="item.id">
      <slot name="body" :item="item" :index="index"></slot>
    </tr>
    </tbody>
  </table>
</template>

<style scoped lang="less">
.table-case {
  width: 1000px;
  margin: 50px auto;
  img {
    width: 100px;
    height: 100px;
    object-fit: contain;
    vertical-align: middle;
  }
}

.my-table {
  width: 100%;
  border-spacing: 0;
  img {
    width: 100px;
    height: 100px;
    object-fit: contain;
    vertical-align: middle;
  }
  th {
    background: #f5f5f5;
    border-bottom: 2px solid #069;
  }
  td {
    border-bottom: 1px dashed #ccc;
  }
  td,
  th {
    text-align: center;
    padding: 10px;
    transition: all .5s;
    &.red {
      color: red;
    }
  }
  .none {
    height: 100px;
    line-height: 100px;
    color: #999;
  }
}

.my-tag {
  cursor: pointer;
  .input {
    appearance: none;
    outline: none;
    border: 1px solid #ccc;
    width: 100px;
    height: 40px;
    box-sizing: border-box;
    padding: 10px;
    color: #666;
    &::placeholder {
      color: #666;
    }
  }
}
</style>

MyTag.vue

<script>
  export default {
    data () {
      return {
        isEdit: false
      }
    },
    props: {
      value: String
    },
    methods: {
      handleClick () {
        // 双击显示
        this.isEdit = true
        // this.$nextTick 是 Vue 实例的一个方法,用于延迟回调的执行,直到下次 DOM 更新完成后(原因是 Vue 是异步更新)
        // 等 dom 更新完了再聚焦
        // this.$nextTick(() => {
        //   // 立刻获取焦点
        //   this.$refs.inp.focus()
        // })
        // 因为是重复调用所以可以封装到全局指令 v-focus
      },

      // 参数 e 是事件对象
      handleEnter (e) {
        // 非空处理
        if (e.target.value.trim() === '') return alert('标签内容不能为空')

        // 子传父
        // 由于父组件是 v-model,触发事件,需要触发 input 事件
        // e.target.value:将输入框的值作为参数传递给事件
        this.$emit('input', e.target.value)
        // 修改完后隐藏输入框
        this.isEdit = false
      }
    }
  }
</script>

<template>
  <div class="my-tag">
    <!-- v-if v-else 控制输入框 -->

    <!-- ref="inp" 解析:-->
    <!-- ref 属性用于注册引用信息。通过给 DOM 元素或子组件添加 ref 属性,你可以在组件的实例中通过 this.$refs 访问到对应的 DOM 元素或子组件实例 -->
    <!-- ref="inp" 表示将输入框元素注册为组件实例的 $refs 对象中的 inp 属性。因此,你可以在组件的方法中通过 this.$refs.inp 访问到这个输入框元素 -->

    <!-- 失去焦点关闭输入框 -->
    <!-- @blur 是一种事件监听的简写语法,用于监听 DOM 元素上的失去焦点(blur)事件 -->

    <!-- :value:这是 Vue 的属性绑定语法,用于将 DOM 元素的属性值与 Vue 实例的数据属性绑定 -->
    <input v-if="isEdit" v-focus @blur="isEdit = false" :value="value" @keyup.enter="handleEnter"
      class="input"
      type="text"
      placeholder="输入标签"
    />
    <!-- @dblclick 是一个事件监听的简写语法,用于监听 DOM 元素上的双击事件 -->
    <div class="text" v-else @dblclick="handleClick">{{ value }}</div>
  </div>
</template>

<style scoped lang="less">
.my-tag {
  cursor: pointer;
  .input {
    appearance: none;
    outline: none;
    border: 1px solid #ccc;
    width: 100px;
    height: 40px;
    box-sizing: border-box;
    padding: 10px;
    color: #666;
    &::placeholder {
      color: #666;
    }
  }
}
</style>

main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

// 封装全局指令 focus
// Vue.directive 是 Vue 的一个全局 API,用于注册全局自定义指令
// 'focus' 是指令的名称,这里定义了一个名为 focus 的指令
// { ... } 是一个对象,定义了该指令的钩子函数
Vue.directive('focus', {
  // inserted 钩子在被绑定元素插入到 DOM 中时被调用
  // el 是钩子函数的参数,表示被绑定的 DOM 元素
  // el.focus() 是一个 DOM 方法,用于将焦点移动到指定的元素上。在这个钩子函数中,一旦元素被插入到 DOM 中,就会自动调用 focus 方法,使得该元素获得焦点
  inserted(el) {
    el.focus()
  }
})

new Vue({
  render: h => h(App),
}).$mount('#app')

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

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

相关文章

力扣刷题----42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图&#xf…

经验分享:大数据信用报告可以查到什么?哪里能查大数据?

相信不少人都因为大数据信用不良碰过壁&#xff0c;这时候不少人反过来想要了解大数据信用报告可以查到什么?哪里能查大数据?其实大数据信用报告就是通过对个人在互联网上产生的各类行为数据收集、整合和分析&#xff0c;并基于此对个人信用状况进行评估和预测的一种检测工具…

Java之快速排序

快速排序 快速排序(Quick Sort)算法&#xff0c;简称快排&#xff0c;利用的是分治的思想。 快速排序思路&#xff1a; ​ 如果要对 first->end 之间的数列进行排序&#xff0c;我们选择 first->end 之间的任意一个元素数据作为分区点(轴值Pivot)&#xff0c;然后遍历 f…

【Qt】QLabel常用属性相关API

QLabel是Qt框架中用于显示文本或图案的小部件。在Qt应用程序中&#xff0c;QLabel是用来呈现静态文本或图像给用户的重要部分 QLabel属性陈列 属性说明textQLabel中的文本内容textFormat 文本的格式 Qt::PlainText 纯文本Qt::RichText 富文本Qt::MarkdownText markdown…

Transformer--输入部分

&#x1f3f7;️上文我们简单介绍了Transformer模型的总体架构&#xff0c;本章我们主要介绍其输入部分 &#x1f4d6;前言 &#x1f4d6;文本嵌入层的作用 &#x1f4d6;位置编码器的作用 &#x1f4d6;前言 输入部分主要包括源文本嵌入层以及位置编码器&#xff0c;目标文本…

【Vulnhub系列】Vulnhub_SecureCode1靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_SecureCode1靶场渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境配置 1、从百度网盘下载对应靶机的.ova镜像 2、在VM中选择【打开】该.ova 3、选择存储路径&#xff0…

高效管理基础设施:掌握 Terraform 的 templatefile 函数技巧

由于Terraform的许可证变更&#xff0c;我曾经担心未来的动向&#xff0c;但IBM宣布收购HashiCorp后&#xff0c;我感到有所安心。我将继续关注相关动向。 本文将介绍Terraform的内置函数templatefile。 什么是templatefile函数&#xff1f; templatefile函数用于读取指定路…

Ip2region - 基于xdb离线库的Java IP查询工具提供给脚本调用

文章目录 Pre效果实现git clone编译测试程序将ip2region.xdb放到指定目录使用改进最终效果 Pre OpenSource - Ip2region 离线IP地址定位库和IP定位数据管理框架 Ip2region - xdb java 查询客户端实现 效果 最终效果 实现 git clone git clone https://github.com/lionsou…

用SQL将数值转换为进度条

hi&#xff0c;大家好呀&#xff01; 最近天气是真的热&#xff0c;上周我们在某音做了一次直播&#xff0c;主要是讲解一下表&#xff0c;那我们最近的会在视频号&#xff0c;也就是微信上给大家直播讲解一下查询&#xff0c;直播预告晚点会分享给大家&#xff0c;请大家关注…

队列queue介绍

队列是一种常见的数据结构&#xff0c;它遵循FIFO&#xff08;先进先出&#xff09;的原则&#xff0c;即最先进入队列的元素将最先被移除。队列在Java中有多种实现方式&#xff0c;其中包括&#xff1a; 1.ArrayDeque&#xff1a;这是一个基于数组的双端队列&#xff0c;可以在…

模拟实现短信登录功能 (session 和 Redis 两种代码实例) 带前端演示

目录 整体流程 发送验证码 短信验证码登录、注册 校验登录状态 基于 session 实现登录 实现发送短信验证码功能 1. 前端发送请求 2. 后端处理请求 3. 演示 实现登录功能 1. 前端发送请求 2. 后端处理请求 校验登录状态 1. 登录拦截器 2. 注册拦截器 3. 登录完整…

Boost_Searcher测试用例编写

功能描述&#xff1a; 用户在客户端页面&#xff0c;在搜索框输入关键词&#xff0c;页面将显示Boost库中所有包含该关键词的内容。 界面功能兼容性易用性安全性性能弱网安装/卸载 编写测试用例&#xff1a; 功能&#xff1a; 在浏览器搜索框中输入ip地址与端口号&#xff0…

MySQL的库操作和表操作

文章目录 MYSQLSQL语句分类服务器&#xff0c;数据库和表的关系 库操作表操作 MYSQL SQL语句分类 DDL【data definition language】 数据定义语言&#xff0c;用来维护存储数据的结构代表指令: create, drop, alterDML【data manipulation language】 数据操纵语言&#xff0…

Playwright 的使用

Playwright 的特点 支持当前所有主流浏览器&#xff0c;包括 Chrome 和 Edge &#xff08;基于 Chromiuns&#xff09;, Firefox , Safari 支持移动端页面测试&#xff0c;使用设备模拟技术&#xff0c;可以让我们在移动Web 浏览器中测试响应式的 Web 应用程序 支持所有浏览…

做一个能和你互动玩耍的智能机器人之四--固件

在openbot的firmware目录下我们能够找到arduino的固件源码和相关的文档。 openbot的controller目录下&#xff0c;是控制器的代码目录&#xff0c;用来控制机器人做一些动作。未来的目标是加入大模型&#xff0c;使其能够理解人的语言和动作来控制。 固件代码&#xff0c;支持…

数据结构 -- 算法的时间复杂度和空间复杂度

数据结构 -- 算法的时间复杂度和空间复杂度 1.算法效率1.1 如何衡量一个算法的好坏1.2 算法的复杂度 2.时间复杂度2.1 时间复杂度的概念2.2 大O的渐进表示法2.3常见时间复杂度计算举例 3.空间复杂度4. 常见复杂度对比 1.算法效率 1.1 如何衡量一个算法的好坏 如何衡量一个算法…

数据库实验:SQL Server基本表单表查询

一、实验目的&#xff1a; 1、掌握使用SQL语法实现单表查询 二、实验内容&#xff1a; 1. 查询订购日期为2001年5月22日的订单情况。&#xff08;Orders&#xff09;&#xff08;时间日期的表达方式为 dOrderDate ‘2001-5-22’&#xff0c;类似字符串&#xff0c;使用单引号…

Linux---git工具

目录 初步了解 基本原理 基本用法 安装git 拉取远端仓库 提交三板斧 1、添加到缓存区 2、提交到本地仓库 3、提交到远端 其他指令补充 多人协作管理 windows用户提交文件 Linux用户提交文件 初步了解 在Linux中&#xff0c;git是一个指令&#xff0c;可以帮助我们做…

Python爬虫-中国汽车市场月销量数据

前言 本文是该专栏的第34篇,后面会持续分享python爬虫干货知识,记得关注。 在本文中,笔者将通过某汽车平台,来采集“中国汽车市场”的月销量数据。 具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。废话不多说,下面跟着笔者直接往下看正文详细内容。(附…