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

CSDN 2024-08-16 08:03:02 阅读 78

前言

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

核心特性

声明式渲染

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

组件系统

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

单文件组件 (SFC)

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

虚拟 DOM

Vue.js 使用虚拟 DOM 来优化视图更新,通过最小化实际 DOM 操作,提高性能。

反应式数据绑定

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

指令

Vue.js 提供了一组内置指令,如 <code>v-bind、v-modelv-for,可以轻松操作 DOM。

优点

易于上手

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

灵活性

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

高性能

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

强大的生态系统

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

活跃的社区

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

<code><template>

<div class="table-case">code>

<MyTable :data="goods">code>

<!-- 使用 <template #head> 来指定插入到子组件 head 插槽的内容 -->

<template #head>

<th>编号</th>

<th>图片</th>

<th>名称</th>

<th>标签</th>

</template>

<!-- slotProps:这是一个插槽属性对象,包含了父组件通过插槽传递给子组件的数据 -->

<template #body="slotProps">code>

<td>{ { slotProps.index + 1 }}</td>

<td><img :src="slotProps.item.picture" alt="#"/></td>code>

<td>{ { slotProps.item.name }}</td>

<td>

<!-- 父传子 -->

<MyTag v-model="slotProps.item.tag"></MyTag>code>

</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>code>

</style>

MyTable.vue

<script>

export default ({

props: {

data: {

type: Array,

required: true

}

}

})

</script>

<template>

<table class="my-table">code>

<thead>

<tr>

<!-- <slot> 是一种用于组件内容分发的机制,允许你将内容从父组件传递到子组件 -->

<!-- <slot> 元素被称为插槽(slot),它定义了子组件中可以插入内容的位置 -->

<!-- name="head":这是一个可选的属性,用于为插槽指定一个名称。通过名称,你可以在父组件中指定哪些内容应该插入到这个插槽中 -->code>

<slot name="head"></slot>code>

</tr>

</thead>

<tbody>

<tr v-for="(item, index) in data" :key="item.id">code>

<slot name="body" :item="item" :index="index"></slot>code>

</tr>

</tbody>

</table>

</template>

<style scoped lang="less">code>

.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">code>

<!-- v-if v-else 控制输入框 -->

<!-- ref="inp" 解析:-->code>

<!-- ref 属性用于注册引用信息。通过给 DOM 元素或子组件添加 ref 属性,你可以在组件的实例中通过 this.$refs 访问到对应的 DOM 元素或子组件实例 -->

<!-- ref="inp" 表示将输入框元素注册为组件实例的 $refs 对象中的 inp 属性。因此,你可以在组件的方法中通过 this.$refs.inp 访问到这个输入框元素 -->code>

<!-- 失去焦点关闭输入框 -->

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

<!-- :value:这是 Vue 的属性绑定语法,用于将 DOM 元素的属性值与 Vue 实例的数据属性绑定 -->

<input v-if="isEdit" v-focus @blur="isEdit = false" :value="value" @keyup.enter="handleEnter"code>

class="input"code>

type="text"code>

placeholder="输入标签"code>

/>

<!-- @dblclick 是一个事件监听的简写语法,用于监听 DOM 元素上的双击事件 -->

<div class="text" v-else @dblclick="handleClick">{ { value }}</div>code>

</div>

</template>

<style scoped lang="less">code>

.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')



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。