Featured image of post 第三章 组件基础(上)

第三章 组件基础(上)

Vue API 风格

组合式 API 和选项式 API 各有优缺点,组合式 API 的主要优势在于更强的逻辑复用和组合能力、更好的类型推导和类型安全、更清晰的逻辑隔离、灵活的逻辑组合和嵌套,以及更方便的测试。选项式 API 在 Vue 2 中广泛使用,仍然是一个强大和有效的选择,但对于复杂逻辑的管理和复用,组合式 API 提供了更现代化的解决方案。

选项式 API(Vue2)

使用选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,如 datamethodsmounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue 2 Options API Example</title>
    <!-- 引入 Vue 2  -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <p>Count: {{ count }}</p>
        <button @click="increment">点击增加</button>
    </div>

    <script>
        new Vue({
            el: '#app',
            data() {
                return {
                    count: 0
                };
            },
            methods: {
                increment() {
                    this.count++;
                }
            }
        });
    </script>
</body>

</html>

组合式 API(Vue3)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue 3 Composition API Example</title>
  <!-- 引入 Vue 3  -->
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

<body>
    <div id="app">
        <p>Count: {{ count }}</p>
        <button @click="increment">点击增加</button>
    </div>

    <script>
        // 从 Vue 全局对象中解构出 createApp 和 ref 函数
        const { createApp, ref } = Vue;

        // 使用 createApp 函数创建一个 Vue 应用实例
        const app = createApp({
            // setup 函数是 Vue 3 组合式 API 的入口点
            setup() {
                // 使用 ref 函数创建一个响应式变量 count,初始值为 0
                const count = ref(0);

                // 定义一个箭头函数 increment,用于增加 count 的值
                const increment = () => {
                    // 通过 count.value 访问和修改 ref 包装的值
                    count.value++;
                };

                // setup 函数返回一个对象,将响应式变量和方法暴露给模板使用
                return {
                    count,
                    increment
                };
            }
        });

        // 调用 app.mount 方法将 Vue 应用挂载到 id 为 app 的 DOM 元素上
        app.mount('#app');
    </script>
</body>

</html> 

两种API风格都能够覆盖大部分的应用场景。它们只是同一个底层系统所提供的两套不同的接口。

  • 当你不需要使用构建工具,或者打算主要在低复杂度的场景中使用 Vue,例如渐进增强的应用场景,推荐采用选项式 API。
  • 当你打算用 Vue 构建完整的单页应用,推荐采用组合式 API + 单文件组件。

创建 Vue 工程

使用 vue-cli 创建

备注:目前 vue-cli 已处于维护模式,官方推荐基于 Vite 创建项目。(点击查看官方文档

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version

## 安装或者升级你的@vue/cli 
npm install -g @vue/cli

## 执行创建命令
vue create vue_test

##  随后选择3.x
##  Choose a version of Vue.js that you want to start the project with (Use arrow keys)
##  > 3.x
##    2.x

## 启动
cd vue_test
npm run serve

使用 vite 创建

vite 是新一代前端构建工具,官网地址:https://vitejs.cnvite 的优势如下:

  • 轻量快速的热重载(HMR),能实现极速的服务启动
  • TypeScriptJSXCSS 等支持开箱即用,不需要配置其他文件
  • 真正的按需编译,不再等待整个应用编译完成。
  • webpack 构建 与 vite 构建对比图如下:

具体操作如下(点击查看官方文档

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
## 1.创建命令
npm create vue@latest

## 2.具体配置
## 配置项目名称
     Project name: vue3_test
## 是否添加TypeScript支持
     Add TypeScript? » Yes
## 是否添加JSX支持
     Add JSX Support? » No
## 是否添加路由环境
     Add Vue Router for Single Page Application development? » No
## 是否添加pinia环境
     Add Pinia for state management? » No
## 是否添加单元测试
     Add Vitest for Unit Testing? » No
## 是否添加端到端测试方案
     Add an End-to-End Testing Solution? » No
## 是否添加ESLint语法检查
     Add ESLint for code quality? » Yes
## 是否添加Prettiert代码格式化
     Add Prettier for code formatting? » No

问题:

npm create vue@latest、和 npm install 速度慢或无法执行。

解决方法:

​ 查看 npm 代理 → npm config get registry

​ 更换 npm 镜像 → npm config set registry=https://registry.npmmirror.com

1
2
3
4
5
## 安装依赖 node_modules
    npm i

## 让 ts 能够识别 .jpg .txt 等文件
    /// <reference types="vite/client" /> 

安装官方推荐的 vscode 插件:

梳理项目的结构:使用vite创建项目-CSDN博客

  • node_modules 目录用来存放第三方依赖包

  • public 是公共的静态资源目录

  • src 是项目的源代码目录(程序员写的所有代码都要放在此目录下)

  • gitignore 是 Git 的忽略文件

  • index.html 是 SPA 单页面应用程序中唯一的 HTML 页面

  • package.json 是项目的包管理配置文件

  • assets 目录用来存放项目中所有的静态资源文件(css、fonts等)

  • components 目录用来存放项目中所有的自定义组件

  • App.vue 是项目的根组件

  • index.css 是项目的全局样式表文件

  • main.js 是整个项目的打包入口文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  "name": "vue-study",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^3.4.21"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.4",
    "vite": "^5.1.6"
  }
}

观察 main.ts 文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import './assets/main.css'

// 这行代码从 vue 库中导入了 createApp 函数。在 Vue 3 里,createApp 是创建 Vue 应用实例的核心函数,借助它可以初始化一个新的 Vue 应用。
import { createApp } from 'vue'

// 此代码导入了根组件 App.vue。App.vue 一般是 Vue 项目的根组件,它包含了整个应用的基本结构与布局。
import App from './App.vue'

// createApp(App):调用 createApp 函数,把 App 组件当作参数传入,从而创建一个新的 Vue 应用实例。
// .mount('#app'):调用 mount 方法,将创建好的 Vue 应用实例挂载到 HTML 文件里 id 为 app 的 DOM 元素上。通常,这个 id 为 app 的元素是在 index.html 文件中定义的。
createApp(App).mount('#app')

总结:

  • Vite 项目中,index.html 是项目的入口文件,在项目最外层。
  • 加载 index.html 后,Vite 解析 <script type="module" src="xxx"> 指向的 JavaScript
  • Vue3 **中是通过 **createApp 函数创建一个应用实例。

项目内语法

export default

在 Vue 3 里,export default 是 ES6 模块语法的一部分,其用途是从一个模块里导出一个默认的值。在 Vue 组件里,它通常用来导出组件的配置对象。

在 Vue 3 的单文件组件(.vue 文件)里,export default 用于导出组件的配置对象,此对象包含组件的选项,像 datamethodscomputed 等。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
  <div>
    <h1>{{ message }}</h1>
    <button @click="changeMessage">修改消息</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: '欢迎使用 Vue 3'
    };
  },
  methods: {
    changeMessage() {
      this.message = '消息已更新';
    }
  }
};
</script>

<style scoped>
h1 {
  color: blue;
}
</style>

插值表达式

删除 src 文件夹下 components 文件夹中的所有文件,清空 App.vue 中所有内容,删除 main.js 文件中语句 import './assets/main.css'

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<template>
<p>{{ m1 }}</p>
</template>

<script>
export default {
  data() {
    return {
      m1: '插值表达式',
      count: 0
    }
  }
}
</script>

属性绑定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<template>
  <img v-bind:src="img5" alt="" class="c1">
  <img :src="img2" alt="" :class="{ active1: true, active2: false }">
  <img :src="img6" alt="" :class="['active1', 'active2']">
</template>

<script>
export default {
  data() {
    return {
      img1: '../img/film1.webp',
      img2: '../img/film2.webp',
      img3: '../img/film3.webp',
      img4: '../img/film4.webp',
      img5: '../img/film5.webp',
      img6: '../img/film6.webp',
      c1: "active1",
      c2: "active2"
    }
  }
}
</script>

<style>
img{
  margin: 20px;
  box-sizing: border-box;
}
.active1 {
  width: 300px;
}
.active2 {
  width: 500px;
  border: 20px solid black;
}
</style>

条件渲染和列表渲染

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
  <img v-bind:src="img5" alt="" v-if="flag">
  <p v-for="(item, index) in list">{{ item }} 的索引号是 {{ index }}</p>
</template>

<script>
export default {
  data() {
    return {
      img1: '../img/film1.webp',
      img2: '../img/film2.webp',
      img3: '../img/film3.webp',
      img4: '../img/film4.webp',
      img5: '../img/film5.webp',
      img6: '../img/film6.webp',
      flag: true,
      list: [
        '111',
        '222',
        '333',
        '444'
      ]
    }
  }
}
</script>

<style>

</style>

事件和计算属性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
  <button @click="add($event)">{{ count }}</button>
  <p>{{ getSum }}</p>
</template>

<script>
export default {
  data() {
    return {
      count: 0,
      list: [1, 2, 3, 4, 5]
    }
  },
  methods: {
    add(e) {
      this.count++;
      console.log(e);
    }
  },
  computed: {
    getSum() {
      let sum = 0;
      for (let i = 0; i < this.list.length; i++) {
        sum += this.list[i];
      }
      return sum;
    }
  }
}
</script>

<style></style>

侦听器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<template>
  <p>{{ message }}</p>
  <button @click="reset">重置</button>
</template>

<script>
export default {
  data() {
    return {
      message: '旧消息'
    }
  },
  methods: {
    reset() {
      this.message = '新消息'
    }
  },
  watch: {
    message(newValue, oldValue) {
      console.log(newValue, oldValue)
    },
    // message(m1, m2) {
    //   console.log(m1, m2)
    // }
  }
}
</script>

<style></style>

拓展:如果希望点击按钮能够在 “旧消息” 和 “新消息” 之间来回切换,怎样实现?

阶段案例

参照以下图片,完成 “学习计划表” 案例,页面中会展示学生的学习计划,包括学习科目、学习内容、学习地点、完成状态等。

使用 vue + html + css 完成案例,实现添加、删除、完成状态变化等功能。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<template>
  <div class="header">
    <h2>学习计划表</h2>
    <div class="card">
      <div class="card-item">
        <span class="item-head">学习科目</span>
        <textarea v-model="subject" name="" id="" placeholder="请输入学习科目"></textarea>
      </div>
      <div class="card-item">
        <span class="item-head">学习内容</span>
        <textarea v-model="content" name="" id="" placeholder="请输入学习内容"></textarea>
      </div>
      <div class="card-item">
        <span class="item-head">学习地点</span>
        <select name="" id="" v-model="space">
          <option :value="index + 1" v-for="(item, index) in spaceList">{{ item.place }}</option>
        </select>
      </div>
      <button @click="add()">添加</button>
    </div>
  </div>
  <div class="main">
    <table>
      <thead>
        <th>序号</th>
        <th>学习科目</th>
        <th>学习内容</th>
        <th>学习地点</th>
        <th>完成状态</th>
        <th>操作</th>
      </thead>
      <tbody>
        <tr v-for="(item, index) in list" :key="item.id">
          <td style="width: 65px;">{{ index + 1 }}</td>
          <td style="width: 300px;">{{ item.subject }}</td>
          <td style="width: 500px;">{{ item.content }}</td>
          <td style="width: 120px;">{{ item.space }}</td>
          <td>
            <input type="checkbox" v-model="item.finished" :disabled="item.finished">
            {{ item.finished ? '已完成' : '未完成' }}
          </td>
          <td style="width: 65px;"><a href="javascript:;" @click="del(item.id)">删除</a></td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>

export default {
  data() {
    return {
      list: [
        { id: 1, subject: 'vue.js前端开发实战', content: '学习vue指令,如v-if、v-for、v-model等', space: '自习室', finished: false },
        { id: 2, subject: 'bootstrap', content: '百度首页仿写', space: '教室', finished: true },
      ],
      spaceList: [
        { placeCode: 1, place: '自习室' },
        { placeCode: 2, place: '教室' },
        { placeCode: 3, place: '图书馆' },
        { placeCode: 4, place: '办公室' },
        { placeCode: 5, place: '宿舍' }
      ],
      subject: '',
      content: '',
      space: 1,
      finished: ''
    }
  },
  methods: {
    add() {
      this.list.unshift({
        id: +new Date(),
        subject: this.subject,
        content: this.content,
        space: this.spaceList[this.space - 1].place,
        finished: false
      })
      console.log(this.list);

    },
    del(id) {
      // this.list = this.list.filter(item => item.id !== id)
      for (let i = 0; i < this.list.length; i++) {
        if (this.list[i].id == id) {
          this.list.splice(i, 1)
        }
      }
    }
  }
}
</script>

<style>
* {
  margin: 0;
}

body {
  min-width: 1200px;
}

.header {
  border: 2px solid black;
  margin: 10px;
  width: 1200px;
}

h2 {
  height: 40px;
  line-height: 40px;
  padding: 0 10px;
  border-bottom: 2px solid gray;
  background-color: lightgray;
}

.card {
  padding: 20px 10px;
  display: flex;
  justify-content: space-between;
}

.card .card-item {
  display: flex;
  margin-right: 20px;
  height: 50px;
}

.card .card-item .item-head {
  background-color: lightgray;
  border: 1px solid black;
  width: 70px;
  line-height: 50px;
  padding: 0 5px;
}

.card .card-item textarea {
  line-height: 40px;
  font-size: 20px;
  padding: 5px;
  border: 1px solid black;
  border-radius: 0;
  outline: none;
  position: relative;
  left: -1px;
  width: 200px;
}

select {
  border-radius: 0;
  position: relative;
  left: -1px;
  font-size: 16px;
  padding: 5px;
  width: 200px;
  outline: none;
}

.card button {
  background-color: lightgray;
  border-radius: 0;
  width: 70px;
  border: 1px solid black;
  cursor: pointer;
}

.main {
  border: 2px solid black;
  margin: 10px;
  width: 1200px;
}

table {
  border-collapse: collapse;
  width: 100%;
  text-align: center;
  font-size: 18px;
}

th,
td {
  border: 1px solid lightgray;
}

thead {
  height: 40px;
}

tr {
  height: 40px;
}
</style>

获取 dom 元素

虽然 Vue 的声明性渲染模型为我们抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。要实现这一点,我们可以使用特殊的 ref 属性。

1
2
3
<div id="d1" ref="d2">这是一个div标签</div>

console.log(this.$refs.d2);

挂载结束后引用都会被暴露在 this.$refs 之上。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<template>
    <p ref="p1">p标签</p>
    <button @click="getRef">获取dom元素</button>
    <br>
    <br>
    <button @click="reSet">更改元素内容</button>
    <br>
    <br>
    <input type="text" name="" id="" ref="i1" @focus="setValue">
  </template>
  
  <script>
  
  
  export default {
    data() {
      return {
  
      }
    },
    methods: {
      getRef() {
        console.log(this.$refs)
        console.log(this.$refs.p1)
      },
      reSet() {
        this.$refs.p1.innerHTML = '2';
      },
      setValue() {
        this.$refs.i1.value = '1111';
      }
    }
  }
  </script>
  
  <style>
    p{
      font-size: 30px;
    }
  </style>

组件基础

组件组成

组件最大的优势就是可复用性。当使用构建步骤时,我们一般会将 Vue 组件定义在一个单独的 .vue 文件中,这被叫做单文件组件(简称 SFC)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<template>
    <div>承载标签</div>
</template>

<script>
    export default {
        
    }
</script>

<style scoped>
</style>

其中,scoped 表示让该样式只在当前组件中生效。

组件引用(局部注册)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<template>
    <MyComponent />
    <MyComponent></MyComponent>
</template>

<script>
    import MyComponent from "./components/MyComponent.vue";
    export default {
        components:{
            MyComponent,
        }
    }
</script>

<style scoped>
</style>

练习:创建两个组件,其中,第一个组件中有一个 h1 标签和一个图片标签,文字颜色为黑色,当点击图片时,图片和标题都能够循环切换;第二个组件中有一个 p 标签,文字颜色为灰色,在 App 文件中引用这两个组件,具体实现效果如下图所示。

中国34个省级2022年高清行政地图和名称来源解读(值得收藏) - 知乎

App

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<template>
  <C1 />
  <C2 />
</template>

<script>
import C1 from "./components/C1.vue";
import C2 from "./components/C2.vue";

export default {
  components: {
    C1,
    C2,
  }
}
</script>

<style scoped></style>

C1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<template>
    <h1>{{ addresses[count % addresses.length] }}</h1>
    <img :src="maps[count % maps.length]" alt="" @click="change">
</template>

<script>
export default {
    data() {
        return {
            addresses: [
                '北京市',
                '上海市',
                '福建省',
                '湖南省',
                '广东省',
            ],
            maps: [
                '../../images/01.jpg',
                '../../images/02.jpg',
                '../../images/03.jpg',
                '../../images/04.jpg',
                '../../images/05.jpg',
            ]
        }
    },
    props: ['count'],
methods:{
    change(){
        this.$emit('aaa', this.count+1)
    }
},
    emits: ['aaa']
}
</script>

<style>
h1 {
    margin: 50px 100px;
}

img {
    width: 700px;
    float: left;
    margin: 0 100px;
}
</style>

C2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<template>
    <p>{{ desc[count % desc.length].m1 }}</p>
    <p>{{ desc[count % desc.length].m2 }}</p>
</template>

<script>
export default {
    data() {
        return {
            desc: [
                {
                    m1: '北京,简称京,古称幽州、燕京和北平,是中华人民共和国首都,位于华北平原北部,面积1.64万平方千米,2022年人口2184万,生产总值41610亿元。北京是中国政治中心、文化中心、国际交往中心、科技创新中心、国家中心城市和世界著名古都。',
                    m2: '北京历史悠久,作为城市历史可追溯到3000年前,一直是中国北方重镇,与西安、南京、洛阳并称中国四大古都。商周时蓟国在北京建城,春秋时燕国灭蓟后迁都于此,称为燕都或燕京。秦代为蓟县,汉代为幽州,隋朝改幽州为涿郡,唐朝复称幽州。1153年,完颜亮正式建都于北京,称为中都,此后元、明和清三朝均建都北京,元代改称大都,明朝朱棣改称北京沿用至今。'
                },
                {
                    m1: '上海,简称沪,别称申城,位于中国华东地区长江三角洲,是中国最大城市和国际经济、金融、贸易、航运、科技创新中心。面积0.63万平方千米,2022年人口为2475万,GDP为44652亿元。',
                    m2: '古时上海地区渔民发明一种竹编捕鱼工具“扈”,因此被称为“沪渎”。战国时上海是楚国春申君黄歇封邑,故上海别称“申”。上海之称始于宋代,当时上海已成为新兴贸易港口,有十八大浦,其中一条叫上海浦,上海浦西岸设有上海镇。1292年,上海改镇为县,这是上海名称由来。1949年,上海设为直辖市。'
                },
                {
                    m1: '福建,简称闽,省会福州,地处我国东南沿海,与台湾隔海相望,因境内有面积12.4万平方公里,是我国著名侨乡和海上丝绸之路起点,山地和丘陵约占90%,八山一水一分田,森林覆盖率居全国第一。2022年人口4188万,生产总值53109亿元。',
                    m2: '秦始皇统一中国后设闽中郡,汉称为闽越国。唐开元年间设福建节度使,管辖福、建、泉、漳、汀五州,取福州和建州两府首字而得名。元设福建行省,明设福建省至今。因境内有闽江和古为闽越族聚居地,故简称闽。'
                },
                {
                    m1: '湖南,简称湘,省会长沙,位于我国中部和长江中游,是湘楚文化典型代表。面积21.18万平方千米,地势东南西三面环山,北部为平原,地跨长江、珠江两大水系。2022年人口6604万人,生产总值48670亿元。',
                    m2: '两晋时设有湘州。唐朝设湖南观察使,始出现湖南一名。宋置荆湖南路,简称湖南路。元朝设湖广行省,明朝设湖广承宣布政使司,清康熙三年湖广分治,以洞庭湖为界,南为湖南省,北为湖北省。因大部分地区处于洞庭湖以南故名湖南,因省内最大河流湘江流贯南北而简称湘。'
                },
                {
                    m1: '广东,简称粤,省会广州,位于南岭以南,南海之滨,是海上丝绸之路发源地、近代革命策源地、改革开放前沿地,岭南文化重要传承地。面积17.98万平方千米,地势总体北高南低,北部多为山地和高丘陵,南部则为平原和台地。广东是中国第一人口大省和经济大省,人口12656万,生产总值129118亿元,是著名华侨之乡、鱼米之乡和果蔬花木之乡。',
                    m2: '因古地名广信之东,故名“广东”,因春秋战国时为百越之地,而简称粤。宋置广南东路,简称广东路,是广东得名之始。元设广东道,明设广东省,沿袭至今。'
                }
            ]
        }
    },
    props: {
        count: Number
    }
}
</script>

<style>
p {
    color: gray;
    margin: 50px 100px;
    font-size: 20px;
}
</style>

组件嵌套关系

组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成层层嵌套的树状结构,这和我们嵌套 HTML 元素的方式类似,Vue 实现了自己的组件模型,使我们可以在每个组件内封装自定义内容与逻辑。

组件注册

当在 Vue 项目中定义了一个新的组件后,想要在其他组件中引用这个新的组件,需要对新的组件进行注册。Vue 提供了两种注册组件的方式,分别是全局注册局部注册

  • 在实际开发中,如果某些组件只在特定情况下被用到,推荐进行局部注册,即在某个组件中注册。被局部注册的组件只能在当前注册范围内使用。例如:在组件 A 中注册了组件 B,则组件 B 只能在组件 A 中使用,不能在组件 C 中使用。

  • 在实际开发中,如果某个组件使用频率很高,许多组件都会引用这个新的组件,则推荐将该组件全局注册。被全局注册的组件可以在当前 Vue 项目的任何一个组件内引用。

在 Vue 项目 src\main.js 文件中,通过 Vue 应用实例的 component() 方法可以全局注册组件,语法如下:

1
component('组件名称', 需要被注册的组件)

src\main.js 中注册一个全局组件 MyComponent,示例代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import { createApp } from 'vue'
import App from './App.vue'

import MyComponent from './components/MyComponent.vue'

// createApp(App).mount('#app')
const app = createApp(App)

// 一定要在 const app = createApp(App) 和 app.mount('#app') 两行代码中间注册组件
app.component('MyComponent', MyComponent)

app.mount('#app')

全局注册虽然很方便,但有以下几个问题:

  • 全局注册,但并没有被使用的组件无法在生产打包时被自动移除(也叫 “tree-shaking")。如果你全局注册了—个组件,即使它并没有被实际使用,它仍然会出现在打包后的 JS 文件中。

  • 全局注册在大型项目中使项目的依赖关系变得不那么明确。在父组件中使用子组件时,不太容易定位子组件的实现。和使用过多的全局变量一样,这可能会影响应用长期的可维护性。

props 传递数据

组件与组件之间不是完全独立的,而是有交集的,有时候会遇到同一个模块中的多个子组件请求同一份数据的情况,如果在子组件中逐个进行网络请求,会造成代码冗余。Vue 提供了 props 语法,可以让父组件为子组件提供要展示的数据,即在父组件中请求该模块下所有子组件中的网络请求,然后通过 props 将数据传递给子组件。

声明 props

在不使用 setup 语法糖的情况下,可以使用 props 选项声明 props,形式可以使对象或者字符串数组,语法格式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<script>
export default {
    props: {
        自定义属性 A: 类型,
        自定义属性 B: 类型,
        str: String,
        num: Number,
        bol: Boolean,
        arr: Array,
        obj: Object,
        ...
    }
}
</script>

如果不需要限制 props 的类型,可以直接声明 props,语法格式如下:

1
2
3
export default {
    props: ['自定义属性 A', '自定义属性 B', 'str', 'num', 'bol', 'arr', 'obj'...]
}

当使用 setup 语法糖时,可以使用 defineProps() 函数声明 props,语法格式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<script setup>
    const props = defineProps(
        {'自定义属性 A': 类型},
        {'自定义属性 B': 类型},
        {'str': String},
        {'num': Number},
        {'bol': Boolean},
        {'arr': Array},
        {'obj': Object},
        ...
    )
</script>

静态绑定 props

1
<子组件标签名 自定义属性 A = "数据" 自定属性 B = "数据" />

Parent

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<template>
<h1>Parent</h1>
<!-- <Child str="字符串类型数据" :num="111" :arr="['alice', 'bob', 'john']" :obj="{name: '张三', age: '18', gender: '男'}" /> -->
<Child str="字符串类型数据" num="111" bol="true" arr="['alice', 'bob', 'john']" obj="{name: '张三', age: '18', gender: '男'}" />
</template>

<script>
import Child from './Child.vue';
export default{
    components: {
        Child
    }
}
</script>

Child

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
    <h1>Child</h1>
    <p>{{ str }}</p>
    <p>{{ num }}</p>
    <p>{{ bol }}</p>
    <p>{{ arr }}</p>
    <p>{{ obj }}</p>
</template>

<script>
export default {
    // props: {
    //     str: String,
    //     num: Number,
    //     bol: Boolean,
    //     arr: Array,
    //     obj: Object
    // }
    props: ['str', 'num', 'bol', 'arr', 'obj']
}
</script>

App

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<template>
  <Parent />
</template>

<script>
import Parent from "./components/Parent.vue"
export default {
  components: {
    Parent
  }
}
</script>

动态绑定 props

使用 v-bind 动态绑定 props,任意类型的值都可以传给子组件的 props。

Parent

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<h1>Parent</h1>
<Child :str="m0" :num="m1" :bol="m2" :arr="m3" :obj="m4" />
</template>

<script>
import Child from './Child.vue';
export default{
    data(){
        return{
            m0: '你好',
            m1: 111,
            m2: true,
            m3: ['alice', 'bob', 'john'],
            m4: {name: '张三', age: '18', gender: '男'},
        }
    },
    components: {
        Child
    }
}
</script>

Child

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<template>
    <h1>Child</h1>
    <p>{{ str }}</p>
    <p>{{ num }}</p>
    <p>{{ bol }}</p>
    <p>{{ arr }}</p>
    <p>{{ obj }}</p>
</template>

<script>
export default {
    props: ['str', 'num', 'bol', 'arr', 'obj']
}
</script>

App

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<template>
  <Parent />
</template>

<script>
import Parent from "./components/Parent.vue"
export default {
  components: {
    Parent
  }
}
</script>

子传父 $emit

  1. 在子元素中添加按钮,点击按钮时触发事件,使用 this.$emit('方法名','值') 向父组件请求修改数据。
1
2
3
4
5
6
7
8
<!-- 在子组件中需要写在方法里-->
methods:{
    change(){
        this.$emit('aaa', 300)
    }
}
<!-- 在父组件中需要接收相应的事件-->
<Child @aaa="change(a)"></Child>
  1. 父组件需要监听子组件传递过来的方法名,监听到后执行父组件内的方法。

  2. 在父组件的 methods 中提供处理函数,在形参中可以获取到子组件传递过来的值,用于修改数据。

Parent

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<h1>Parent</h1>
<Child :msg="m1" @changeData="change" />
</template>

<script>
import Child from './Child.vue';
export default{
    data(){
        return{
            m1: '尝试修改这条信息',
        }
    },
    components: {
        Child
    },
    methods: {
        change(newData){
            this.m1 = newData;
        }
    }
}
</script>

Child

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<template>
    <h1>Child</h1>
    <p>{{ msg }}</p>
    <button @click="modify">修改数据</button>
</template>

<script>
export default {
    props: ['msg'],
    methods: {
        modify(){
            this.$emit('changeData', '修改后的信息')
        }
    }
}
</script>

App

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<template>
  <Parent />
</template>

<script>
import Parent from "./components/Parent.vue"
export default {
  components: {
    Parent
  }
}
</script>

———————–地图切换———————–

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// --------------c1
<template>
    <h1>{{ addresses[count % addresses.length] }}</h1>
    <img :src="maps[count % maps.length]" alt="" @click="change">
</template>

<script>
export default {
    data() {
        return {
            addresses: [
                '北京市',
                '上海市',
                '福建省',
                '湖南省',
                '广东省',
            ],
            maps: [
                '../../images/01.jpg',
                '../../images/02.jpg',
                '../../images/03.jpg',
                '../../images/04.jpg',
                '../../images/05.jpg',
            ]
        }
    },
    props: ['count'],
    methods:{
        change(){
            this.$emit('aaa', this.count+1)
        }
    },
    emits: ['aaa']
}
</script>

<style>
h1 {
    margin: 50px 100px;
}

img {
    width: 700px;
    float: left;
    margin: 0 100px;
}
</style>

// --------------c2
<template>
    <p>{{ desc[count % desc.length].m1 }}</p>
    <p>{{ desc[count % desc.length].m2 }}</p>
</template>

<script>
export default {
    data() {
        return {
            desc: [
                {
                    m1: '北京,简称京,古称幽州、燕京和北平,是中华人民共和国首都,位于华北平原北部,面积1.64万平方千米,2022年人口2184万,生产总值41610亿元。北京是中国政治中心、文化中心、国际交往中心、科技创新中心、国家中心城市和世界著名古都。',
                    m2: '北京历史悠久,作为城市历史可追溯到3000年前,一直是中国北方重镇,与西安、南京、洛阳并称中国四大古都。商周时蓟国在北京建城,春秋时燕国灭蓟后迁都于此,称为燕都或燕京。秦代为蓟县,汉代为幽州,隋朝改幽州为涿郡,唐朝复称幽州。1153年,完颜亮正式建都于北京,称为中都,此后元、明和清三朝均建都北京,元代改称大都,明朝朱棣改称北京沿用至今。'
                },
                {
                    m1: '上海,简称沪,别称申城,位于中国华东地区长江三角洲,是中国最大城市和国际经济、金融、贸易、航运、科技创新中心。面积0.63万平方千米,2022年人口为2475万,GDP为44652亿元。',
                    m2: '古时上海地区渔民发明一种竹编捕鱼工具“扈”,因此被称为“沪渎”。战国时上海是楚国春申君黄歇封邑,故上海别称“申”。上海之称始于宋代,当时上海已成为新兴贸易港口,有十八大浦,其中一条叫上海浦,上海浦西岸设有上海镇。1292年,上海改镇为县,这是上海名称由来。1949年,上海设为直辖市。'
                },
                {
                    m1: '福建,简称闽,省会福州,地处我国东南沿海,与台湾隔海相望,因境内有面积12.4万平方公里,是我国著名侨乡和海上丝绸之路起点,山地和丘陵约占90%,八山一水一分田,森林覆盖率居全国第一。2022年人口4188万,生产总值53109亿元。',
                    m2: '秦始皇统一中国后设闽中郡,汉称为闽越国。唐开元年间设福建节度使,管辖福、建、泉、漳、汀五州,取福州和建州两府首字而得名。元设福建行省,明设福建省至今。因境内有闽江和古为闽越族聚居地,故简称闽。'
                },
                {
                    m1: '湖南,简称湘,省会长沙,位于我国中部和长江中游,是湘楚文化典型代表。面积21.18万平方千米,地势东南西三面环山,北部为平原,地跨长江、珠江两大水系。2022年人口6604万人,生产总值48670亿元。',
                    m2: '两晋时设有湘州。唐朝设湖南观察使,始出现湖南一名。宋置荆湖南路,简称湖南路。元朝设湖广行省,明朝设湖广承宣布政使司,清康熙三年湖广分治,以洞庭湖为界,南为湖南省,北为湖北省。因大部分地区处于洞庭湖以南故名湖南,因省内最大河流湘江流贯南北而简称湘。'
                },
                {
                    m1: '广东,简称粤,省会广州,位于南岭以南,南海之滨,是海上丝绸之路发源地、近代革命策源地、改革开放前沿地,岭南文化重要传承地。面积17.98万平方千米,地势总体北高南低,北部多为山地和高丘陵,南部则为平原和台地。广东是中国第一人口大省和经济大省,人口12656万,生产总值129118亿元,是著名华侨之乡、鱼米之乡和果蔬花木之乡。',
                    m2: '因古地名广信之东,故名“广东”,因春秋战国时为百越之地,而简称粤。宋置广南东路,简称广东路,是广东得名之始。元设广东道,明设广东省,沿袭至今。'
                }
            ]
        }
    },
    props: {
        count: Number
    }
}
</script>

<style>
p {
    color: gray;
    margin: 50px 100px;
    font-size: 20px;
}
</style>

// --------------app
<template>
  <c1 :count="num" @aaa="me"></c1>
  <c2 :count="num"></c2>
  <!-- <button @click="change">11</button> -->
</template>

<script>
import c1 from './components/c1.vue'
import c2 from './components/c2.vue'
export default {
  data() {
    return {
      num: 0
    }
  },
  components: {
    c1,
    c2
  },
  methods:{
    // change(){
    //   this.num++;
    // },
    me(a){
      this.num = a;
    }
  }
}
</script>

学习计划表传递

Top

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<template>
    <div class="header">
        <h2>学习计划表</h2>
        <div class="card">
            <div class="card-item">
                <span class="item-head">学习科目</span>
                <textarea v-model="subject" name="" id="" placeholder="请输入学习科目"></textarea>
            </div>
            <div class="card-item">
                <span class="item-head">学习内容</span>
                <textarea v-model="content" name="" id="" placeholder="请输入学习内容"></textarea>
            </div>
            <div class="card-item">
                <span class="item-head">学习地点</span>
                <select name="" id="" v-model="space">
                    <option :value="index + 1" v-for="(item, index) in spaceList">{{ item.place }}</option>
                </select>
            </div>
            <button @click="add()">添加</button>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            subject: '',
            content: '',
            space: 1,
            finished: ''
        }
    },
    props: {
        spaceList: Array
    },
    methods: {
        add() {
            this.$emit('aaa', {
                id: +new Date(),
                subject: this.subject,
                content: this.content,
                space: this.spaceList[this.space - 1].place,
                finished: false
            })
        }
    }
}
</script>

Bottom

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<template>
    <div class="main">
        <table>
            <thead>
                <th>序号</th>
                <th>学习科目</th>
                <th>学习内容</th>
                <th>学习地点</th>
                <th>完成状态</th>
                <th>操作</th>
            </thead>
            <tbody>
                <tr v-for="(item, index) in list" :key="item.id">
                    <td style="width: 65px;">{{ index + 1 }}</td>
                    <td style="width: 300px;">{{ item.subject }}</td>
                    <td style="width: 500px;">{{ item.content }}</td>
                    <td style="width: 120px;">{{ item.space }}</td>
                    <td>
                        <input type="checkbox" v-model="item.finished" :disabled="item.finished">
                        {{ item.finished ? '已完成' : '未完成' }}
                    </td>
                    <td style="width: 65px;"><a href="javascript:;" @click="del(item.id)">删除</a></td>
                </tr>
            </tbody>
        </table>
    </div>
</template>

<script>
export default {
    props: {
        list: Array
    },
    methods: {
        del(id) {
            for (let i = 0; i < this.list.length; i++) {
                if (this.list[i].id == id) {
                    this.list.splice(i, 1)
                }
            }
        }
    }
}
</script>

App

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<template>
  <top :spaceList="spaceList" @aaa="add"></top>
  <bottom :list="list"></bottom>
</template>

<script>
import top from './components/studyCard/top.vue'
import bottom from './components/studyCard/bottom.vue'
export default {
  components: {
    top,
    bottom
  },
  data() {
    return {
      list: [
        { id: 1, subject: 'vue.js前端开发实战', content: '学习vue指令,如v-if、v-for、v-model等', space: '自习室', finished: false },
        { id: 2, subject: 'bootstrap', content: '百度首页仿写', space: '教室', finished: true },
      ],
      spaceList: [
        { placeCode: 1, place: '自习室' },
        { placeCode: 2, place: '教室' },
        { placeCode: 3, place: '图书馆' },
        { placeCode: 4, place: '办公室' },
        { placeCode: 5, place: '宿舍' }
      ],
    }
  },
  methods:{
    add(e){
      this.list.unshift(e)
    }
  }
}
</script>

<style>
* {
  margin: 0;
}

body {
  min-width: 1200px;
}

.header {
  border: 2px solid black;
  margin: 10px;
  width: 1200px;
}

h2 {
  height: 40px;
  line-height: 40px;
  padding: 0 10px;
  border-bottom: 2px solid gray;
  background-color: lightgray;
}

.card {
  padding: 20px 10px;
  display: flex;
  justify-content: space-between;
}

.card .card-item {
  display: flex;
  margin-right: 20px;
  height: 50px;
}

.card .card-item .item-head {
  background-color: lightgray;
  border: 1px solid black;
  width: 70px;
  line-height: 50px;
  padding: 0 5px;
}

.card .card-item textarea {
  line-height: 40px;
  font-size: 20px;
  padding: 5px;
  border: 1px solid black;
  border-radius: 0;
  outline: none;
  position: relative;
  left: -1px;
  width: 200px;
}

select {
  border-radius: 0;
  position: relative;
  left: -1px;
  font-size: 16px;
  padding: 5px;
  width: 200px;
  outline: none;
}

.card button {
  background-color: lightgray;
  border-radius: 0;
  width: 70px;
  border: 1px solid black;
  cursor: pointer;
}

.main {
  border: 2px solid black;
  margin: 50px 10px;
  width: 1200px;
}

table {
  border-collapse: collapse;
  width: 100%;
  text-align: center;
  font-size: 18px;
}

th,
td {
  border: 1px solid lightgray;
}

thead {
  height: 40px;
}

tr {
  height: 40px;
}

textarea{
  overflow-y: hidden;
}
</style>

跨级组件之间的数据传递

父子关系组件之间的数据传递主要通过 props$emit 实现,非父子关系组件之间,通过 provideinject 或者 eventbus 传递数据,在复杂的 vue 项目中,使用 vuex 实现组件之间数据传递。

provide() & inject()

父组件provide提供数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
export default {
  provide() {
    return {
      <!-- 可以包含普通数据类型或者复杂数据类型 --> 
      c1: this.c1,
      c2: this.c2
    }
  },
  components: {
    ProvideChild,
  },
  data() {
    return {
      m1: 111,
      m2: 222,
      <!-- c1为字符串类型c2为对象类型 -->   
      c1: 'hello',
      c2: { name: 'zhangsan', age: 18, gender: 'nan' }
    }
  }
}

子 / 孙组件 inject 取值使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
    <div class="child">
        <p>{{ n1 }}</p>
        <p>{{ c1 }}</p>
        <p>{{ c2 }}</p>
        <ProvideGrandChild />
    </div>
</template>

<script>
import ProvideGrandChild from './ProvideGrandChild.vue';
export default {
    <!-- 在后代组件中使用inject数组的形式取值 --> 
    inject: ['c1', 'c2'],
    created() {
        console.log(this.c1, this.c2);
    },
    props: ['n1', 'n2'],
    components:{
        ProvideGrandChild,
    }
}
</script>

APP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<template>
  <div>
    <p>111</p>
    <p>{{ c1 }}</p>
    <p>{{ c2 }}</p>
    <button @click="changeAll">改变数据</button>
    <ProvideChild :n1="m1" :n2="m2" />
  </div>
</template>

<script>
import ProvideChild from "./components/ProvideChild.vue";
export default {
  provide() {
    return {
      c1: this.c1,
      c2: this.c2
    }
  },
  components: {
    ProvideChild,
  },
  data() {
    return {
      m1: 111,
      m2: 222,
      c1: 'hello',
      c2: { name: 'zhangsan', age: 18, gender: 'nan' }
    }
  },
  methods: {
    changeAll() {
      this.c1 = 'changedc1';
      this.c2 = { name: 'xiaozhang', age: 17, gender: 'nv' };
    },
    changeData() {
      this.c2.name = 'xiaozhang';
      this.c2.age = 17;
      this.c2.gender = 'nv'
    }
  }
}
</script>

<style scoped>
div {
  width: 800px;
  height: 800px;
  border: 2px solid black;
}
</style>

ProvideChild

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<template>
    <div class="child">
        <p>{{ n1 }}</p>
        <p>{{ c1 }}</p>
        <p>{{ c2 }}</p>
        <ProvideGrandChild />
    </div>
</template>

<script>
import ProvideGrandChild from './ProvideGrandChild.vue';
export default {
    inject: ['c1', 'c2'],
    created() {
        console.log(this.c1, this.c2);
    },
    props: ['n1', 'n2'],
    components:{
        ProvideGrandChild,
    }
}
</script>

<style scoped>
    .child{
        width: 500px;
        height: 500px;
        border: 2px solid black;
        margin: 30px;
    }
</style>

ProvideGrandChild

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
    <div class="grandchild">
        <p>111</p>
        <!-- <p>{{ n1 }}</p> -->
        <p>{{ c1 }}</p>
        <p>{{ c2 }}</p>
    </div>
</template>

<script>
export default {
    inject: ['c1', 'c2'],
    created() {
        console.log(this.c1, this.c2);
    },
    // props: ['n1', 'n2']
}
</script>

<style scoped>
    .grandchild{
        margin: 30px;
        width: 300px;
        height: 300px;
        border: 2px solid black;
    }
</style>

练习

选择题

  1. 创建 Vue 项目的命令是什么?

A. npm create-vue project B. npm create vue project

C. npm create-react project D. npm create vue@latest

  1. 下列哪个语句可以作为插值表达式中的语句?

A. {{ var a = 1 }} B. {{ if (ok) { return message } }}

C. {{ message.split(’’).reverse().join(’’) }} D. {{ if (ok) { } else { } }}

  1. 下列哪个是侦听器关键字?

A. data B. methods C. computed D. watch

  1. 在 Vue 中,传递参数过程中获取 event 对象的写法正确的是?

A. @click = “getNameHandle(item)”

B. @click = “getNameHandle(item, $event)”

C. @click = “getNameHandle(item, e)”

D. @click = “getNameHandle(e)”

案例——学习计划表

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<template>
  <div class="card">
    <div class="card-header"><span><strong>学习计划表</strong></span></div>
    <div class="card-body">
      <form>
        <div class="mod"><span>学习科目 <input type="text" v-model="subject"></span></div>
        <div class="mod"><span>学习内容 <input type="text" v-model="content"></span></div>
        <div class="mod">
          <span>学习地点
            <select v-model="location">
              <option value="1">图书馆</option>
              <option value="2">自习室</option>
              <option value="3">宿舍</option>
              <option value="4">咖啡厅</option>
              <option value="5">办公室</option>
            </select>
          </span>
        </div>
        <div>
          <button type="button" @click="add">添加</button>
        </div>
      </form>
    </div>
  </div>
  <br>
  <div class="list">
    <table>
      <thead>
        <tr>
          <th>序号</th>
          <th>学习科目</th>
          <th>学习内容</th>
          <th>学习地点</th>
          <th>完成状态</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item, index) in lists" :key="item.id">
          <td>{{ index + 1 }}</td>
          <td>{{ item.subject }}</td>
          <td>{{ item.content }}</td>
          <td>{{ item.location }}</td>
          <td><input type="checkbox" class="check" @click="finish(item.id)"><span>{{ item.status }}</span></td>
          <td><a href="javascript:;" @click="del(item.id)">删除</a></td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      lists: [
        { id: 1, subject: 'vue.js', content: 'vue指令', location: '图书馆', status: '未完成' },
      ],
      subject: '',
      content: '',
      location: '1',
      status: '未完成'
    }
  },
  methods: {
    add() {
      if (!this.subject) {
        alert('学习科目不能为空!');
        return;
      }
      if (!this.content) {
        alert('学习内容不能为空!');
        return;
      }
      this.lists.push({
        id: +new Date(),
        subject: this.subject,
        content: this.content,
        location: document.querySelectorAll('option')[this.location - 1].innerHTML,
        status: this.status
      })
      this.subject = ''
      this.content = ''
      console.log(this.lists);
    },
    del(id) {
      // this.list = this.list.filter(item => item.id !== id)
      let index = 0;
      for (let i = 0; i < this.lists.length; i++) {
        if (this.lists[i].id === id) {
          index = i;
        }
      }
      if(document.querySelectorAll('.check')[index].checked == false){
        alert('请先完成计划再删除!');
        return;
      }
      // console.log(this.list)
      this.lists.splice(index, 1);
      // console.log(this.list)
    },
    finish(id){
      let index = 0;
      for (let i = 0; i < this.lists.length; i++) {
        if (this.lists[i].id === id) {
          index = i;
        }
      }
      // document.querySelectorAll('.check')[index].checked == true;
      document.querySelectorAll('td span')[index].innerHTML = '已完成';
      document.querySelectorAll('.check')[index].disabled = true;
    }
  }
}
</script>

<style scoped>
* {
  font-size: 24px;
}

.card {
  width: 100%;
  height: 200px;
  border: 2px solid gray;
}

.card-header {
  height: 50px;
  background-color: lightgray;
  line-height: 50px;
  border-bottom: 2px solid gray;
}

.card-header span {
  margin-left: 20px;
}

.card-body button {
  float: left;
  margin: 50px 20px;
  height: 50px;
}

.mod {
  float: left;
  margin: 50px 20px;
  background-color: lightgray;
  height: 48px;
  border: 2px solid gray;
}

.mod input {
  height: 44px;
  margin-top: -1px;
  margin-right: -2px;
  outline: none;
}

.mod select {
  height: 50px;
  margin-top: -1px;
  margin-right: -2px;
  width: 150px;
  text-align: center;
  outline: none;
}

.mod span {
  margin-left: 5px;
}

.list {
  width: 100%;
}

.list table {
  width: 100%;
  border-spacing: 0;
  border-top: 2px solid gray;
  border-left: 2px solid gray;
}

.list table th {
  background: lightgray;
}

.list table td:hover {
  background: #f5f5f5;
}

.list table th,
.list table td {
  border-bottom: 2px solid gray;
  border-right: 2px solid gray;
  text-align: center;
  padding: 10px;
}

input[type="checkbox"] {
  width: 20px;
  height: 20px;
}
</style>

案例——百度热搜

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
<template>
  <!-- <ul>
      <li v-for="(item, index) in lis"><span v-if="index == 0" :class="{ s0: index == 0 }">#</span><span
          :class="{ s0: index == 1, s1: index == 2, s2: index == 3, s3: index > 3 }" v-else>{{ index }}</span><a
          href="#">{{ item.title }}</a></li>
    </ul> -->
  <div class="main-box">
    <div class="head">
      <img src="../../img/baidu.png" alt="">
      <div class="title">
        <strong>百度热搜 ></strong>
        <span class="next-icon" @click="next">↻ 换一换</span>
      </div>
    </div>
    <div class="tab">
      <span class="tab-item active" @click="show(0)">热搜榜</span>
      <span class="tab-item" @click="show(1)">长沙榜</span>
      <span class="tab-item" @click="show(2)">民生榜</span>
      <span class="tab-item" @click="show(3)">财经榜</span>
    </div>
    <div class="list" v-for="(item, index) in tab1lis1" :key="item.id" v-show="page % 2 == 1 && tab % 4 == 0">
      <div class="news"><span v-if="index == 0" :class="{ s0: index == 0 }">#</span><span
          :class="{ s0: index == 1, s1: index == 2, s2: index == 3, s3: index > 3 }" v-else>{{ index }}</span><a
          href="#">{{ item.title }}</a></div>
    </div>
    <div class="list" v-for="(item, index) in tab1lis2" :key="item.id" v-show="page % 2 == 0 && tab % 4 == 0">
      <div class="news"><span class="s3">{{ index + 10 }}</span><a href="#">{{ item.title }}</a></div>
    </div>
    <div class="list" v-for="(item, index) in tab2lis1" :key="item.id" v-show="tab % 4 == 1">
      <div class="news"><span :class="{ s0: index == 0, s1: index == 1, s2: index == 2, s3: index > 2 }">{{ index + 1
          }}</span><a href="#">{{ item.title }}</a></div>
    </div>
    <div class="list" v-for="(item, index) in tab3lis1" :key="item.id" v-show="tab % 4 == 2">
      <div class="news"><span :class="{ s0: index == 0, s1: index == 1, s2: index == 2, s3: index > 2 }">{{ index + 1
          }}</span><a href="#">{{ item.title }}</a></div>
    </div>
    <div class="list" v-for="(item, index) in tab4lis1" :key="item.id" v-show="tab % 4 == 3">
      <div class="news"><span :class="{ s0: index == 0, s1: index == 1, s2: index == 2, s3: index > 2 }">{{ index + 1
          }}</span><a href="#">{{ item.title }}</a></div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tab1lis1: [
        { id: 1, title: '风好正是扬帆时' },
        { id: 2, title: '住建部:防止房地产市场大起大落热' },
        { id: 3, title: '美国共产主义者宣布成立政党' },
        { id: 4, title: '2024年全国两会新闻中心启用' },
        { id: 5, title: '上海到北京仅需2.5小时' },
        { id: 6, title: '爆火的秦岭隧道视频系拼接 作者道歉' },
        { id: 7, title: '贵州省长:全面清理拖欠企业账款' },
        { id: 8, title: '理想市值一天涨了1个小鹏' },
        { id: 9, title: '#张雪峰称想出国读书先看这本书#' },
        { id: 10, title: '河南多地发生山火?' },
      ],
      tab1lis2: [
        { id: 11, title: '演唱会黄牛煽动粉丝冲卡被行拘' },
        { id: 12, title: '端午节放3天不调休' },
        { id: 13, title: '美媒称拜登支持率与特朗普仅差1%' },
        { id: 14, title: '澳亿万富豪之女在悉尼袭击案中遇害' },
        { id: 15, title: '华为P系列升级为华为Pura' },
        { id: 16, title: '老板掉进化粪池6人施救不幸全遇难' },
        { id: 17, title: '阿根廷总统米莱宣布与女友分手' },
        { id: 18, title: '我国已记录660多种外来入侵物种' },
        { id: 19, title: '官方回应128元千人宴全是花生毛豆' },
        { id: 20, title: '副县长妻子为出轨对象做间谍17年' },
      ],
      tab2lis1: [
        { id: 1, title: '民生项目落地 长沙幸福“加码”' },
        { id: 2, title: '发展新质生产力,长沙瞄准有生力“量”' },
        { id: 3, title: '长沙:未经业主同意,不得擅自涨物业费' },
        { id: 4, title: '长沙望城区:调解劳资纠纷工会“快”字当头' },
        { id: 5, title: '长沙诚邀您用镜头寻最美“乡”味' },
        { id: 6, title: '2024中部(长沙)糖酒会将启幕' },
        { id: 7, title: '2024长沙马栏山花朝节开幕' },
        { id: 8, title: '2028年通车!长沙城南将新增一座过江大桥' },
        { id: 9, title: '长沙量子测量产业技术研究院揭牌' },
        { id: 10, title: '听说,五一广场成了长沙“粤语区”' },
      ],
      tab3lis1: [
        { id: 1, title: '翻船目击者称因吃饭躲过一劫' },
        { id: 2, title: '35辆车高速集体爆胎' },
        { id: 3, title: '北大凌晨讣告:大师辞世' },
        { id: 4, title: '墨西哥城一直升机坠毁' },
        { id: 5, title: '南京司机拒载日本乘客系谣言' },
        { id: 6, title: '重庆辟谣“一家人上吊而死”' },
        { id: 7, title: '1735名村民起诉区政府' },
        { id: 8, title: '26岁男生失联家属发声' },
        { id: 9, title: '国家某部委翻译驻外期被策反' },
        { id: 10, title: '炸串奶奶摊前排起长队' },
      ],
      tab4lis1: [
        { id: 1, title: '章泽天自曝家族有帕金森基因' },
        { id: 2, title: '油价明天预计上调' },
        { id: 3, title: '周鸿祎等企业家在飞机上掼蛋' },
        { id: 4, title: '万科承认遇到经营困难' },
        { id: 5, title: '我国人均存款约10.8万' },
        { id: 6, title: '高盛上调年底金价预测' },
        { id: 7, title: '章泽天现身美国参加名流晚宴' },
        { id: 8, title: '科大讯飞与华中师范大学合作' },
        { id: 9, title: '苹果面临日本加重罚款' },
        { id: 10, title: '1-3月中国进口钢材减少' },
      ],
      page: 1,
      tab: 0
    }
  },
  methods: {
    next() {
      this.page++;
    },
    show(index) {
      const items = document.querySelectorAll('.tab-item');
      const active = document.querySelector('.active');
      active.classList.remove('active');
      items[index].classList.add('active');
      this.tab = index;
      this.page = 1;
    }
  }
}
</script>

<style scoped>
.main-box {
  width: 300px;
  text-wrap: nowrap;
  overflow-x: hidden;
  /* text-overflow: ellipsis; */
  overflow-y: hidden;
  position: absolute;
  top: 30%;
  left: 50%;
  /* 往上(x轴)、左(y轴)移动自身长宽的 50%,以使其居于中心位置。 */
  transform: translate(-50%, -50%);
}

img {
  width: 101px;
  height: 33px;
  margin-bottom: -2.5px;
}

.list {
  height: 35px;
  padding: 5px 0;
  box-sizing: border-box;
}

a {
  text-decoration: none;
  color: rgb(36, 64, 179);
  font-size: 16px;
}

a:hover {
  color: rgb(41, 91, 255);
  text-decoration: underline;
}

.title {
  margin: 15px 0;
}

.title strong {
  width: 150px;
  font-size: 22px;
  cursor: pointer;
}

.title strong:hover {
  color: rgb(41, 91, 255);
}

.next-icon {
  margin-left: 120px;
  color: rgb(98, 102, 117);
  cursor: pointer;
}

.next-icon:hover {
  color: rgb(41, 91, 255);
}

.tab {
  margin: 15px 0;
}

.tab-item {
  background-color: rgb(238, 238, 238);
  margin-left: 20px;
  width: 60px;
  height: 28px;
  /* border: 1px solid black; */
  border-radius: 5px;
  display: inline-block;
  text-align: center;
  line-height: 28px;
  color: rgb(36, 64, 179);
  cursor: pointer;
}

.tab-item:hover {
  color: rgb(41, 91, 255);
  background-color: rgb(227, 237, 255);
}

.tab-item:nth-child(1) {
  margin-left: 0;
}

.active {
  color: rgb(41, 91, 255);
  background-color: rgb(227, 237, 255);
}

.s0 {
  color: rgb(255, 0, 0);
}

.s1 {
  color: rgb(255, 102, 0);
}

.s2 {
  color: rgb(250, 169, 14);
}

.s3 {
  color: rgb(145, 149, 163);
}

.list .news span {
  border-radius: 50%;
  width: 20px;
  height: 20px;
  margin-right: 10px;
  font-size: 16px;
  display: inline-block;
}
</style>

案例——小米商场

练习:仿照小米官网,思考如何划分组件,编写样式,引入组件完成页面设计。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<template>
    <div class="bg">
        <div class="container">
            <ul class="left">
                <li v-for="(item, index) in leftList">
                    {{ item }}
                    <span v-if="index != leftList.length - 1">|</span>
                </li>
            </ul>
            <ul class="right">
                <li v-for="(item, index) in rightList">
                    <!-- <router-link :to="item.linkTo" class="title"> -->
                        {{ item.title }}
                    <!-- </router-link> -->
                    <span v-if="index != rightList.length - 1">|</span>
                </li>
                <!-- <router-link to="/shop"> -->
                    <li class="shop" ref="shopItem">
                        <svg t="1745197484153" class="icon" viewBox="0 0 1028 1024" version="1.1"
                            xmlns="http://www.w3.org/2000/svg" p-id="2689" width="20" height="20">
                            <path
                                d="M332.8 790.528q19.456 0 36.864 7.168t30.208 19.968 20.48 30.208 7.68 36.864-7.68 36.864-20.48 30.208-30.208 20.48-36.864 7.68q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-36.864 7.68-36.864 20.48-30.208 30.208-19.968 37.888-7.168zM758.784 792.576q19.456 0 37.376 7.168t30.72 19.968 20.48 30.208 7.68 36.864-7.68 36.864-20.48 30.208-30.72 20.48-37.376 7.68-36.864-7.68-30.208-20.48-20.48-30.208-7.68-36.864 7.68-36.864 20.48-30.208 30.208-19.968 36.864-7.168zM930.816 210.944q28.672 0 44.544 7.68t22.528 18.944 6.144 24.064-3.584 22.016-13.312 37.888-22.016 62.976-23.552 68.096-18.944 53.248q-13.312 40.96-33.28 56.832t-49.664 15.872l-35.84 0-65.536 0-86.016 0-96.256 0-253.952 0 14.336 92.16 517.12 0q49.152 0 49.152 41.984 0 20.48-9.728 35.84t-38.4 14.336l-49.152 0-94.208 0-118.784 0-119.808 0-99.328 0-55.296 0q-20.48 0-34.304-9.216t-23.04-24.064-14.848-32.256-8.704-32.768q-1.024-6.144-5.632-29.696t-11.264-58.88-14.848-78.848-16.384-87.552q-19.456-103.424-44.032-230.4l-76.8 0q-15.36 0-25.6-7.68t-16.896-18.432-9.216-23.04-2.56-22.528q0-20.48 13.824-33.792t37.376-12.288l103.424 0q20.48 0 32.768 6.144t19.456 15.36 10.24 18.944 5.12 16.896q2.048 8.192 4.096 23.04t4.096 30.208q3.072 18.432 6.144 38.912l700.416 0zM892.928 302.08l-641.024-2.048 35.84 185.344 535.552 1.024z"
                                p-id="2690" fill="#b0b0b0"></path>
                        </svg>
                        购物车
                        <span class="shopCount">({{ count }})</span>
                    </li>
                <!-- </router-link> -->
                <!-- 方法1router-link + to 跳转到指定地址 -->
            </ul>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            leftList: [
                '小米官网', '小米商场', '小米澎湃 OS', 'IOT', '云服务', '天星数科',
                '有品', '小爱开放平台', '资质证照', '协议规则', '下载 APP', 'Select Location'
            ],
            // rightList: [
            //     '登录', '注册', '消息通知'
            // ],
            rightList: [
                { title: '登录', linkTo: '/login' },
                { title: '注册', linkTo: '/register' },
                { title: '消息通知', linkTo: '/info' },
            ],
            count: 0,
        }
    },
    mounted() {
        // console.log(this.$refs.shopItem);
        let shop = document.querySelector('.shop');
        shop.addEventListener('mouseenter', () => {
            document.querySelector('path').style.fill = 'rgb(255, 103, 0)';
            document.querySelector('.shopCount').style.color = 'rgb(255, 103, 0)';
            shop.classList.add('active')
        })
        shop.addEventListener('mouseleave', () => {
            document.querySelector('path').style.fill = '#b0b0b0';
            document.querySelector('.shopCount').style.color = '#b0b0b0';
            shop.classList.remove('active')
        })
    },
    // 方法2:使用 method 处理事件实现跳转
    // methods: {
    //     toShop(){
    //         this.$router.push('/shop')
    //     }
    // }
}
</script>

<style scoped>
.bg {
    min-width: 1226px;
    background-color: rgb(51, 51, 51);
}

.container {
    width: 1226px;
    margin: 0 auto;
    height: 40px;
}

ul {
    height: 40px;
    line-height: 40px;
    font-size: 12px;
}

.left {
    float: left;
}

.right {
    float: right;
}

ul li {
    float: left;
    list-style: none;
    /* margin: 0 10px; */
    padding: 0 5px;
    color: rgb(176, 176, 176);
}

span {
    /* margin-left: 16px; */
    position: relative;
    left: 4px;
    color: rgb(114, 114, 114);
}

.shop {
    width: 110px;
    background-color: rgb(66, 66, 66);
    text-align: center;
    margin-left: 25px;
}

.shop.active {
    background-color: rgb(255, 255, 255);
    color: rgb(255, 103, 0);
}

.shopCount {
    color: rgb(176, 176, 176);
}

ul li:hover {
    color: white;
    cursor: pointer;
}

svg {
    position: relative;
    top: 5px;
    left: -5px;
}

.title {
    color: rgb(176, 176, 176);
    text-decoration: none;
}

.title:hover {
    color: white;
}
</style>

Tab

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<template>
    <div class="container">
        <img src="../../../images/xiaomi/logo-mi2.png" alt="">
        <ul>
            <!-- <li v-for="item in list">{{ item }}</li> -->
            <li v-for="item in list">
                <!-- <router-link :to="item.linkTo"> -->
                    {{ item.title }}
                <!-- </router-link> -->
            </li>
        </ul>
        <div class="search">
            <input type="text" placeholder="2025米粉节">
            <button>
                <svg t="1745200046674" class="icon" viewBox="0 0 1024 1024" version="1.1"
                    xmlns="http://www.w3.org/2000/svg" p-id="3786" width="20" height="20">
                    <path
                        d="M959.266 879.165c0 81.582-81.582 81.582-81.582 81.582l-233.38-233.381c-60.529 43.977-134.777 70.217-215.318 70.217-202.755 0-367.117-164.362-367.117-367.117S226.23 63.349 428.985 63.349s367.117 164.362 367.117 367.117c0 80.541-26.241 154.785-70.217 215.318l233.381 233.381zM428.985 144.931c-157.697 0-285.536 127.838-285.536 285.536s127.838 285.536 285.536 285.536 285.536-127.838 285.536-285.536-127.839-285.536-285.536-285.536z"
                        fill="#8a8a8a" p-id="3787"></path>
                </svg>
            </button>
        </div>
    </div>

</template>

<script>
export default {
    data() {
        return {
            // list: [
            //     'Xiaomi 手机', 'Redmi 手机', '电视', '笔记本', '平板', '家电', '路由器', '服务中心', '社区'
            // ],
            list: [
                {title: 'Xiaomi 手机', linkTo: '/shop/phone'},
                {title: 'Redmi 手机', linkTo: '/shop/phone'},
                {title: '电视', linkTo: '/shop/pad'},
                {title: '笔记本', linkTo: '/shop/pad'},
                {title: '平板', linkTo: '/shop/pad'},
                {title: '家电', linkTo: '/shop/elec'},
                {title: '路由器', linkTo: '/shop/smart'},
                {title: '服务中心', linkTo: '/'},
                {title: '社区', linkTo: '/'},
            ]
        }
    }
}
</script>

<style scoped>
img {
    width: 56px;
    float: left;
    position: relative;
    top: 22px;
}

.container {
    height: 100px;
    width: 1226px;
    margin: 0 auto;
    overflow: hidden;
}

ul {
    height: 24px;
    line-height: 24px;
    position: relative;
    top: 38px;
    left: 160px;
    width: 700px;
}

ul li {
    float: left;
    list-style: none;
    padding: 0 10px;
}

ul li a{
    text-decoration: none;
    color: black;
}

ul li a:hover {
    color: rgb(255, 128, 9);
    cursor: pointer;
}

ul li a.fuzzy-active{
    color: rgb(255, 128, 9);
}

.search {
    width: 296px;
    height: 50px;
    display: flex;
    float: right;
}

button {
    width: 52px;
    border: 1px solid rgb(224, 224, 224);
    background: #fff;
}

input {
    width: 243px;
    border: 1px solid rgb(224, 224, 224);
    outline: none;
    box-sizing: border-box;
    padding: 0 10px;
    font-size: 14px;
    border-right: 0;
}
</style>

Wrapper

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
<template>
    <div class="container" @click="nextImg" ref="bg">
        <!-- <div class="container" @click="count++" ref="bg" :style="{ backgroundImage: test[count % test.length]}"> -->
        <!-- :class="{ bg1: count % bgList.length == 0, bg2: count % bgList.length == 1, bg3: count % bgList.length == 2, bg4: count % bgList.length == 3, bg5: count % bgList.length == 4, bg6: count % bgList.length == 5 }" -->
        <ul>
            <li v-for="item in list">
                <a href="">
                    {{ item }}
                    <span>
                        <svg t="1745202463487" class="icon" viewBox="0 0 1024 1024" version="1.1"
                            xmlns="http://www.w3.org/2000/svg" p-id="4940" width="20" height="20">
                            <path
                                d="M332.501333 183.168a42.666667 42.666667 0 0 1 57.621334-2.496l2.709333 2.496 298.666667 298.666667a42.666667 42.666667 0 0 1 2.496 57.621333l-2.496 2.709333-298.666667 298.666667a42.666667 42.666667 0 0 1-62.826667-57.621333l2.496-2.709334L600.96 512 332.501333 243.498667a42.666667 42.666667 0 0 1-2.496-57.621334l2.496-2.709333z"
                                fill="#ffffff" p-id="4941"></path>
                        </svg>
                    </span>
                </a>
            </li>
        </ul>
        <div class="left">
            <svg t="1745207869866" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
                p-id="6132" width="50" height="50">
                <path
                    d="M300 511.4l363 436.1c12.2 14.6 33.9 16.6 48.5 4.4 14.6-12.2 16.6-33.9 4.4-48.5l-326.2-392L716 120.5c12.2-14.6 10.2-36.3-4.4-48.5-14.6-12.2-36.4-10.2-48.6 4.4l-363 435z"
                    fill="rgb(176, 176, 176)" p-id="6133"></path>
            </svg>
        </div>
        <div class="right">
            <svg t="1745207985607" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
                p-id="10595" width="50" height="50">
                <path
                    d="M680.96 536.32L294.826667 149.76C281.6 136.533333 281.6 115.2 294.826667 101.546667c13.226667-13.226667 34.986667-13.226667 48.213333 0l386.133333 386.133333c13.226667 13.226667 13.226667 34.986667 0 48.213333-13.226667 13.653333-34.986667 13.653333-48.213333 0.426667z"
                    fill="rgb(176, 176, 176)" p-id="10596"></path>
                <path
                    d="M294.826667 874.24l386.133333-386.133333c13.226667-13.226667 34.986667-13.226667 48.213333 0 13.226667 13.226667 13.226667 34.986667 0 48.213333l-386.133333 386.133333c-13.226667 13.226667-34.986667 13.226667-48.213333 0-13.226667-13.653333-13.226667-34.986667 0-48.213333z"
                    fill="rgb(176, 176, 176)" p-id="10597"></path>
            </svg>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            list: [
                '手机', '电视', '家电', '笔记本 平板', '出行 穿戴', '耳机 音箱',
                '健康 儿童', '生活 箱包', '智能 路由器', '电源 配件'
            ],
            // bgList: [
            //     '../../../images/xiaomi/i1.jpg',
            //     '../../../images/xiaomi/i2.webp',
            //     '../../../images/xiaomi/i3.webp',
            //     '../../../images/xiaomi/i4.webp',
            //     '../../../images/xiaomi/i5.webp',
            //     '../../../images/xiaomi/i6.webp',
            // ],
            test: [
                'url(../../../images/xiaomi/i1.jpg)',
                'url(../../../images/xiaomi/i2.webp)',
                'url(../../../images/xiaomi/i3.webp)',
                'url(../../../images/xiaomi/i4.webp)',
                'url(../../../images/xiaomi/i5.webp)',
                'url(../../../images/xiaomi/i6.webp)'
            ],
            count: 4
        }
    },
    mounted() {
        this.$refs.bg.style.backgroundImage = this.test[4]
    },
    methods: {
        nextImg() {
            this.count++;
            this.$refs.bg.style.backgroundImage = this.test[this.count % this.test.length]
        }
    }
}
</script>

<style scoped>
/* .bg1 {
    background-image: url(../../../images/xiaomi/i1.jpg);
}

.bg2 {
    background-image: url(../../../images/xiaomi/i2.webp);
}

.bg3 {
    background-image: url(../../../images/xiaomi/i3.webp);
}

.bg4 {
    background-image: url(../../../images/xiaomi/i4.webp);
}

.bg5 {
    background-image: url(../../../images/xiaomi/i5.webp);
}

.bg6 {
    background-image: url(../../../images/xiaomi/i6.webp);
} */

.container {
    width: 1226px;
    margin: 0 auto;
    /* background-image: url(../../../images/xiaomi/i5.webp); */
    height: 460px;
    background-size: contain;
    overflow: hidden;
    position: relative;
}

ul {
    width: 234px;
    height: 420px;
    padding: 20px 0;
    background-color: rgba(105, 101, 101, 0.6);
}

ul li {
    list-style: none;
    font-size: 14px;
    line-height: 42px;
    height: 42px;
    cursor: pointer;
}

a {
    display: inline-block;
    box-sizing: border-box;
    width: 234px;
    line-height: 42px;
    text-decoration: none;
    color: white;
    padding-left: 30px;
}

ul li:hover {
    background-color: rgb(255, 103, 0);
}

span {
    float: right;
    position: relative;
    right: 20px;
    top: 5px;
}

.left,
.right {
    width: 40px;
    height: 70px;
    /* background-color: aqua; */
    background-color: rgba(0, 0, 0, 0);
    cursor: pointer;
}

.left {
    float: left;
    position: absolute;
    top: 195px;
    left: 234px;
}

.left svg {
    position: relative;
    left: -6px;
    top: 10px;
}

.right {
    float: right;
    position: absolute;
    top: 195px;
    right: 0px;
    /* left: 900px; */
}

.right svg {
    position: relative;
    left: -1px;
    top: 10px;
}

.left:hover {
    background-color: rgb(51, 51, 51);
}

.right:hover {
    background-color: rgb(51, 51, 51);
}
</style>
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
<template>
    <div class="container">
        <div class="span4">
            <ul class="home-channel-list">
                <li>
                    <img src="../../../images/xiaomi/banner1.png" alt="">
                    保障服务
                </li>
                <li>
                    <img src="../../../images/xiaomi/banner2.png" alt="">
                    企业团购
                </li>
                <li>
                    <img src="../../../images/xiaomi/banner3.png" alt="">
                    F码通道
                </li>
                <li>
                    <img src="../../../images/xiaomi/banner4.png" alt="">
                    米粉卡
                </li>
                <li>
                    <img src="../../../images/xiaomi/banner5.png" alt="">
                    以旧换新
                </li>
                <li>
                    <img src="../../../images/xiaomi/banner6.png" alt="">
                    话费充值
                </li>
            </ul>
        </div>
        <div class="span16">
            <ul class="home-promo-list">
                <li>
                    <img src="../../../images/xiaomi/banner-b-1.png" alt="">
                </li>
                <li>
                    <img src="../../../images/xiaomi/banner-b-2.png" alt="">
                </li>
                <li>
                    <img src="../../../images/xiaomi/banner-b-3.png" alt="">
                </li>
            </ul>
        </div>
    </div>
</template>

<style scoped>
.container {
    width: 1226px;
    height: 170px;
    margin: 0 auto;
    margin-top: 14px;
    margin-bottom: 20px;
    display: flex;
}

.span4 {
    width: 234px;
    height: 170px;
}

.home-channel-list {
    width: 234px;
    height: 170px;
    background-color: rgb(95, 87, 80);
    padding: 3px;
    box-sizing: border-box
}

.home-channel-list li {
    width: 70px;
    height: 82px;
    padding: 0 3px;
    float: left;
    list-style: none;
    font-size: 12px;
    color: white;
    text-align: center;
}

.home-channel-list li img{
    width: 24px;
    height: 24px;
    margin: 0 23px;
    padding-top: 18px;
}

.home-promo-list li {
    list-style: none;
    float: left;
    margin-left: 15px;
}

.home-promo-list li:first-child{
    margin-left: 0;
}

.home-promo-list li img {
    width: 316px;
    height: 170px;
}

.span16 {
    margin-left: 14px;
}
</style>

Item

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<template>
    <div class="goods">
        <!-- <div class="goods-img">
            <img src="../../../images/xiaomi/REDMI Turbo 4 Pro.webp" alt="">
        </div>
        <h3 class="title">Redmi Turbo 3</h3>
        <p class="desc">性能旋风席卷而来</p>
        <p class="price"></p> -->
        <slot></slot>
    </div>
</template>

<style>
.goods {
    width: 234px;
    height: 300px;
    box-sizing: border-box;
    padding: 20px 0;
    text-align: center;
    font-size: 14px;
    font-family: "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei", "Hiragino Sans GB", "Heiti SC", "WenQuanYi Micro Hei", sans-serif;
    cursor: pointer;
    background-color: white;
    transition: 0.5s;
    float: left;
    margin: 0 0 14px 14px;
    user-select: none;
}

.goods:hover {
    box-shadow: 0 0 15px #cccccc;
    transform: translate(0, -2px);
}

.goods-img img {
    width: 160px;
    height: 160px;
}

.goods h3 {
    font-size: 14px;
}

.goods h3,
.goods p {
    margin: 0;
    font-weight: 100;
}

.goods .desc {
    margin: 10px;
    color: rgb(176, 176, 176);
    font-size: 12px;
    text-overflow: ellipsis;
    overflow: hidden;
    text-wrap: nowrap;
}

.goods .price {
    color: rgb(255, 103, 0);
}
</style>

<script>

</script>

MoreItem

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
<template>
    <div class="more-item">
        <div class="mini-item">
            <slot name="mini-item">
                <h3 class="title">
                    Xiaomi 开放式耳机
                </h3>
                <p class="price">599</p>
                <div class="mini-img">
                    <img src="../../../images/xiaomi/watch&bud/mini-Xiaomi 开放式耳机.webp" alt="">
                </div>
            </slot>
        </div>
        <div class="see-more">
            <div class="title">
                浏览更多
                <slot name="more-small">
                    <small>耳机</small>
                </slot>
            </div>
            <svg t="1745805142422" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
                p-id="12820" width="60" height="60">
                <path
                    d="M510.247 959.053c238.627 0 432.77-196.2 432.77-437.351 0-241.153-194.143-437.353-432.77-437.353-238.627 0-432.772 196.202-432.772 437.353 0 241.15 194.143 437.351 432.772 437.351z m0-820.035c208.804 0 378.675 171.665 378.675 382.684 0 211.013-169.871 382.68-378.675 382.68S131.57 732.715 131.57 521.702c0-211.02 169.871-382.684 378.677-382.684zM293.862 549.035h367.472L545.218 666.38c-10.563 10.677-10.563 27.976 0 38.654a26.849 26.849 0 0 0 38.251 0l162.288-164.01c10.567-10.675 10.567-27.975 0-38.651L583.469 338.361c-5.283-5.337-12.205-8.004-19.124-8.004-6.924 0-13.841 2.667-19.127 8.004-10.563 10.679-10.563 27.974 0 38.654l116.116 117.35H293.862c-14.953 0-27.047 12.225-27.047 27.336 0 15.107 12.092 27.333 27.047 27.333z"
                    p-id="12821" fill="#FF6700">
                </path>
            </svg>
        </div>
    </div>
</template>

<style>
.more-item {
    width: 234px;
    height: 300px;
    float: left;
    margin-left: 14px;
}

.more-item .mini-img img {
    width: 80px;
    height: 80px;
    position: relative;
    top: -90px;
    left: 130px;
}

.mini-item,
.see-more {
    width: 234px;
    height: 143px;
    margin-bottom: 14px;
    background-color: #fff;
    transition: 0.5s;
    cursor: pointer;
    padding: 50px 0;
    box-sizing: border-box;
}

.mini-item .title {
    font-size: 14px;
    font-weight: 400;
    width: 94px;
    height: 42px;
    margin: 0 110px 0 30px;
    line-height: 21px;
}

.mini-item .price {
    color: rgb(255, 103, 0);
    width: 91px;
    height: 21px;
    margin: 5px 110px 0 30px;
    font-size: 14px;
}

.mini-item:hover,
.see-more:hover {
    box-shadow: 0 0 15px #cccccc;
    transform: translate(0, -2px);
}

.see-more .title {
    width: 94px;
    height: 45px;
    margin: 0 110px 0 30px;
    font-size: 18px;
    line-height: 27px;
}

.see-more small {
    display: block;
    color: rgb(117, 117, 117);
    font-size: 12px;
    height: 18px;
    line-height: 18px;
}

.see-more svg {
    position: relative;
    top: -55px;
    left: 140px;
}
</style>

Goods

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
<template>
    <div class="bgc">
        <div class="box-hd">
            <slot name="title">
                <h2 class="title">手机</h2>
            </slot>
            <div class="more">
                <slot name="more">
                    <a href="javascript:;">
                        查看更多
                        <svg t="1745725757152" class="icon" viewBox="0 0 1024 1024" version="1.1"
                            xmlns="http://www.w3.org/2000/svg" p-id="4256" width="20" height="20">
                            <path
                                d="M512 102.4a422.912 422.912 0 1 0 422.570667 423.936A422.570667 422.570667 0 0 0 512 102.4z m117.418667 446.805333L462.506667 716.8a34.133333 34.133333 0 0 1-48.469334-48.128l143.018667-143.018667-143.018667-143.018666a34.133333 34.133333 0 0 1 0-48.128 34.133333 34.133333 0 0 1 48.469334 0l166.912 166.912a34.133333 34.133333 0 0 1 0 49.152z"
                                fill="#b0b0b0" p-id="4257">
                            </path>
                        </svg>
                    </a>
                </slot>
            </div>
        </div>
        <div class="main-box">
            <div class="left-img">
                <slot name="left-img">
                    <img src="../../../images/xiaomi/phone/left-phone.webp" alt="">
                    <!-- <ul>
                        <li class="top-img">
                            <img src="../../../images/xiaomi/elec/xiaomielec1.webp" alt="">
                        </li>
                        <li class="bottom-img">
                            <img src="../../../images/xiaomi/elec/xiaomielec2.webp" alt="">
                        </li>
                    </ul> -->
                </slot>
            </div>
            <div class="right-goods">
                <!-- <Item v-for="(item, index) in itemList">
                    <div class="goods-img">
                        <img :src="item.src" alt="">
                    </div>
                    <h3 class="title">{{ item.title }}</h3>
                    <p class="desc">{{ item.desc }}</p>
                    <p class="price">{{ item.price }}</p>
                </Item> -->
                <slot name="right-goods"></slot>
            </div>
        </div>
    </div>
</template>

<script>
import Item from './Item.vue'
export default {
    components: {
        Item
    },
    // data() {
    //     return {
    //         itemList: [
    //             { id: 1, src: '../../../images/xiaomi/REDMI Turbo 4 Pro.webp', title: 'REDMI Turbo 4 Pro', desc: 'Turbo 4 Pro 好看,更能打!', price: '1999元起' },
    //             { id: 2, src: '../../../images/xiaomi/Xiaomi 15 Ultra.webp', title: 'Xiaomi 15 Ultra', desc: ' 徕卡1英寸主摄 | 徕卡2亿超级长焦 | 徕卡超纯光学系统 | 骁龙8至尊版移动平台 | 6000mAh 小米金沙江电池 | 小米澎湃OS 2', price: '6499元起' },
    //             { id: 3, src: '../../../images/xiaomi/REDMI Turbo 4.webp', title: 'REDMI Turbo 4', desc: 'REDMI Turbo 4 好看又能打', price: '1799元起' },
    //             { id: 4, src: '../../../images/xiaomi/Redmi 14C.webp', title: 'Redmi 14C', desc: '【持久续航】5160mAh 大电池', price: '499元起' },
    //             { id: 5, src: '../../../images/xiaomi/REDMI K80 Pro.webp', title: 'REDMI K80 Pro', desc: '骁龙8至尊版|2K新国屏|全焦段影像', price: '3699元起' },
    //             { id: 6, src: '../../../images/xiaomi/REDMI K80.webp', title: 'REDMI K80', desc: '第三代骁龙8|2K新国屏|6550mAh 超长续航', price: '2499元起' },
    //             { id: 7, src: '../../../images/xiaomi/Xiaomi 15.webp', title: 'Xiaomi 15', desc: ' 徕卡光学 Summilux 高速镜头|骁龙®8至尊版移动平台|5400mAh 小米金沙江电池 小米澎湃OS 2', price: '4199元起' },
    //             { id: 8, src: '../../../images/xiaomi/Xiaomi 15 Pro.webp', title: 'Xiaomi 15 Pro', desc: '徕卡光学 Summilux 高速镜头| 骁龙®8至尊版移动平台|6100mAh 小米金沙江电池|小米澎湃OS 2', price: '4999元起' },
    //         ]
    //     }
    // }
}
</script>

<style>
.bgc {
    background-color: rgb(245, 245, 245);
    height: 686px;
}

.box-hd {
    height: 58px;
    width: 1226px;
    color: rgb(51, 51, 51);
    display: flex;
    justify-content: space-between;
}

.box-hd h2 {
    font-size: 22px;
    font-weight: 200;
    line-height: 58px
}

.box-hd .more {
    line-height: 58px;
}

.box-hd .more a {
    color: rgb(51, 51, 51);
    text-decoration: none;
}

.main-box {
    width: 1226px;
    display: flex;
}

.left-img {
    /* float: left; */
    cursor: pointer;
}

.left-img img {
    width: 234px;
    height: 614px;
    transition: 0.5s;
}

.left-img img:hover {
    box-shadow: 0 0 15px #cccccc;
    transform: translate(0, -2px);
}

.right-goods {
    width: 992px;
    height: 614px;
}

svg {
    position: relative;
    top: 4px;
}

.left-img li{
    list-style: none;
    margin-bottom: 14px;
}

.left-img .top-img img,
.left-img .bottom-img img{
    width: 234px;
    height: 300px;
}
</style>

Main

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
<template>
    <main>
        <div class="container">
            <div class="home-banner-box">
                <img src="../../../images/xiaomi/main-top.webp" alt="">
            </div>
            <Goods>
                <template #left-img></template>
                <template #right-goods>
                    <Item v-for="(item, index) in itemListPhone">
                        <div class="goods-img">
                            <img :src="item.src" alt="">
                        </div>
                        <h3 class="title">{{ item.title }}</h3>
                        <p class="desc">{{ item.desc }}</p>
                        <p class="price">{{ item.price }}</p>
                    </Item>
                </template>
            </Goods>
            <Goods>
                <template #title>
                    <h2 class="title">智能穿戴</h2>
                </template>
                <template #more>
                    <ul class="tab-list">
                        <li class="active">耳机</li>
                        <li>穿戴</li>
                    </ul>
                </template>
                <template #left-img>
                    <img src="../../../images/xiaomi/watch&bud/left-watch.webp" alt="">
                </template>
                <template #right-goods>
                    <Item v-for="(item, index) in itemListBud">
                        <div class="goods-img">
                            <img :src="item.src" alt="">
                        </div>
                        <h3 class="title">{{ item.title }}</h3>
                        <p class="desc">{{ item.desc }}</p>
                        <p class="price">{{ item.price }}</p>
                    </Item>
                    <MoreItem></MoreItem>
                </template>
            </Goods>
            <Goods>
                <template #title>
                    <h2 class="title">笔记本 | 平板</h2>
                </template>
                <template #more>
                    <ul class="tab-list">
                        <li class="active">热门</li>
                    </ul>
                </template>
                <template #left-img>
                    <img src="../../../images/xiaomi/pad&book/left-pad.webp" alt="">
                </template>
                <template #right-goods>
                    <Item v-for="(item, index) in itemListPad">
                        <div class="goods-img">
                            <img :src="item.src" alt="">
                        </div>
                        <h3 class="title">{{ item.title }}</h3>
                        <p class="desc">{{ item.desc }}</p>
                        <p class="price">{{ item.price }}</p>
                    </Item>
                    <MoreItem>
                        <template #mini-item>
                            <h3 class="title">
                                Redmi Book Pro 14 2024
                            </h3>
                            <p class="price">4999</p>
                            <div class="mini-img">
                                <img src="../../../images/xiaomi/pad&book/mini-Redmi Book Pro 14 2024.webp" alt="">
                            </div>
                        </template>
                        <template #more-small>
                            <small>热门</small>
                        </template>
                    </MoreItem>
                </template>
            </Goods>
            <Goods>
                <template #title>
                    <h2 class="title">家电</h2>
                </template>
                <template #more>
                    <ul class="tab-list">
                        <li class="active">热门</li>
                        <li>电视影音</li>
                        <li>空调</li>
                    </ul>
                </template>
                <template #left-img>
                    <ul>
                        <li class="top-img">
                            <img src="../../../images/xiaomi/elec/left-elec1.webp" alt="">
                        </li>
                        <li class="bottom-img">
                            <img src="../../../images/xiaomi/elec/left-elec2.webp" alt="">
                        </li>
                    </ul>
                </template>
                <template #right-goods>
                    <Item v-for="(item, index) in itemListElec">
                        <div class="goods-img">
                            <img :src="item.src" alt="">
                        </div>
                        <h3 class="title">{{ item.title }}</h3>
                        <p class="desc">{{ item.desc }}</p>
                        <p class="price">{{ item.price }}</p>
                    </Item>
                    <MoreItem>
                        <template #mini-item>
                            <h3 class="title">
                                迷你波轮洗衣机 3kg
                            </h3>
                            <p class="price">799</p>
                            <div class="mini-img">
                                <img src="../../../images/xiaomi/elec/mini-米家迷你波轮洗衣机Pro 3kg.webp" alt="">
                            </div>
                        </template>
                        <template #more-small>
                            <small>热门</small>
                        </template>
                    </MoreItem>
                </template>
            </Goods>
            <Goods>
                <template #title>
                    <h2 class="title">生活电器</h2>
                </template>
                <template #more>
                    <ul class="tab-list">
                        <li class="active">风扇</li>
                        <li>扫地机</li>
                        <li>空净</li>
                        <li>清洁</li>
                        <li>环境</li>
                    </ul>
                </template>
                <template #left-img>
                    <ul>
                        <li class="top-img">
                            <img src="../../../images/xiaomi/cleaner/left-cleaner1.webp" alt="">
                        </li>
                        <li class="bottom-img">
                            <img src="../../../images/xiaomi/cleaner/left-cleaner2.webp" alt="">
                        </li>
                    </ul>
                </template>
                <template #right-goods>
                    <Item v-for="(item, index) in itemListCleaner">
                        <div class="goods-img">
                            <img :src="item.src" alt="">
                        </div>
                        <h3 class="title">{{ item.title }}</h3>
                        <p class="desc">{{ item.desc }}</p>
                        <p class="price">{{ item.price }}</p>
                    </Item>
                    <MoreItem>
                        <template #mini-item>
                            <h3 class="title">
                                米家直流变频台式循环扇
                            </h3>
                            <p class="price">299</p>
                            <div class="mini-img">
                                <img src="../../../images/xiaomi/cleaner/mini-米家直流变频台式循环扇.webp" alt="">
                            </div>
                        </template>
                        <template #more-small>
                            <small>风扇</small>
                        </template>
                    </MoreItem>
                </template>
            </Goods>
            <Goods>
                <template #title>
                    <h2 class="title">厨房电器</h2>
                </template>
                <template #more>
                    <ul class="tab-list">
                        <li>净水器</li>
                        <li class="active">烟灶</li>
                        <li>电饭煲</li>
                        <li>微蒸烤</li>
                    </ul>
                </template>
                <template #left-img>
                    <ul>
                        <li class="top-img">
                            <img src="../../../images/xiaomi/kitchen/left-kitchen1.webp" alt="">
                        </li>
                        <li class="bottom-img">
                            <img src="../../../images/xiaomi/kitchen/left-kitchen2.webp" alt="">
                        </li>
                    </ul>
                </template>
                <template #right-goods>
                    <Item v-for="(item, index) in itemListKitchen">
                        <div class="goods-img">
                            <img :src="item.src" alt="">
                        </div>
                        <h3 class="title">{{ item.title }}</h3>
                        <p class="desc">{{ item.desc }}</p>
                        <p class="price">{{ item.price }}</p>
                    </Item>
                    <MoreItem>
                        <template #mini-item>
                            <h3 class="title">
                                米家智能净烟机P2
                            </h3>
                            <p class="price">299</p>
                            <div class="mini-img">
                                <img src="../../../images/xiaomi/kitchen/mini-米家智能净烟机P2.webp" alt="">
                            </div>
                        </template>
                        <template #more-small>
                            <small>烟灶</small>
                        </template>
                    </MoreItem>
                </template>
            </Goods>
            <Goods>
                <template #title>
                    <h2 class="title">智能家居</h2>
                </template>
                <template #more>
                    <ul class="tab-list">
                        <li class="active">小爱音箱</li>
                        <li>门锁门铃</li>
                        <li>路由器</li>
                        <li>智能设备</li>
                    </ul>
                </template>
                <template #left-img>
                    <ul>
                        <li class="top-img">
                            <img src="../../../images/xiaomi/smart/left-smart1.webp" alt="">
                        </li>
                        <li class="bottom-img">
                            <img src="../../../images/xiaomi/smart/left-smart2.webp" alt="">
                        </li>
                    </ul>
                </template>
                <template #right-goods>
                    <Item v-for="(item, index) in itemListSmart">
                        <div class="goods-img">
                            <img :src="item.src" alt="">
                        </div>
                        <h3 class="title">{{ item.title }}</h3>
                        <p class="desc">{{ item.desc }}</p>
                        <p class="price">{{ item.price }}</p>
                    </Item>
                    <MoreItem>
                        <template #mini-item>
                            <h3 class="title">
                                Redmi小爱触屏音箱 8英寸
                            </h3>
                            <p class="price">299</p>
                            <div class="mini-img">
                                <img src="../../../images/xiaomi/smart/mini-Redmi小爱触屏音箱 8英寸.webp" alt="">
                            </div>
                        </template>
                        <template #more-small>
                            <small>小爱音箱</small>
                        </template>
                    </MoreItem>
                </template>
            </Goods>
            <div class="home-banner-box">
                <img src="../../../images/xiaomi/main-bottom.webp" alt="">
            </div>
        </div>
    </main>
</template>

<script>
import Goods from './Goods.vue';
import Item from './Item.vue';
import MoreItem from './MoreItem.vue';

export default {
    components: {
        Goods,
        Item,
        MoreItem
    },
    data() {
        return {
            itemListPhone: [
                { id: 1, src: '../../../images/xiaomi/phone/REDMI Turbo 4 Pro.webp', title: 'REDMI Turbo 4 Pro', desc: 'Turbo 4 Pro 好看,更能打!', price: '1999元起' },
                { id: 2, src: '../../../images/xiaomi/phone/Xiaomi 15 Ultra.webp', title: 'Xiaomi 15 Ultra', desc: '徕卡1英寸主摄 | 徕卡2亿超级长焦 | 徕卡超纯光学系统 | 骁龙8至尊版移动平台 | 6000mAh 小米金沙江电池 | 小米澎湃OS 2', price: '6499元起' },
                { id: 3, src: '../../../images/xiaomi/phone/REDMI Turbo 4.webp', title: 'REDMI Turbo 4', desc: 'REDMI Turbo 4 好看又能打', price: '1799元起' },
                { id: 4, src: '../../../images/xiaomi/phone/Redmi 14C.webp', title: 'Redmi 14C', desc: '【持久续航】5160mAh 大电池', price: '499元起' },
                { id: 5, src: '../../../images/xiaomi/phone/REDMI K80 Pro.webp', title: 'REDMI K80 Pro', desc: '骁龙8至尊版|2K新国屏|全焦段影像', price: '3699元起' },
                { id: 6, src: '../../../images/xiaomi/phone/REDMI K80.webp', title: 'REDMI K80', desc: '第三代骁龙8|2K新国屏|6550mAh 超长续航', price: '2499元起' },
                { id: 7, src: '../../../images/xiaomi/phone/Xiaomi 15.webp', title: 'Xiaomi 15', desc: '徕卡光学 Summilux 高速镜头|骁龙®8至尊版移动平台|5400mAh 小米金沙江电池 小米澎湃OS 2', price: '4199元起' },
                { id: 8, src: '../../../images/xiaomi/phone/Xiaomi 15 Pro.webp', title: 'Xiaomi 15 Pro', desc: '徕卡光学 Summilux 高速镜头| 骁龙®8至尊版移动平台|6100mAh 小米金沙江电池|小米澎湃OS 2', price: '4999元起' },
            ],
            itemListBud: [
                { id: 1, src: '../../../images/xiaomi/watch&bud/Xiaomi Buds 5 Pro.webp', title: 'Xiaomi Buds 5 Pro', desc: '小米首发双功放三单元|55dB 深度降噪|哈曼联合调音', price: '1299元起' },
                { id: 2, src: '../../../images/xiaomi/watch&bud/REDMI Buds 6 Pro.webp', title: 'REDMI Buds 6 Pro', desc: '小米首发圈瓷同轴三单元 | 55dB深度降噪 | 无级动态降噪技术', price: '399元起' },
                { id: 3, src: '../../../images/xiaomi/watch&bud/Redmi Buds 6 青春版.webp', title: 'Redmi Buds 6 青春版', desc: '42dB深度主动降噪 | 双麦AI通话抗风噪 | 12.4mm超大镀钛动圈', price: '139元起' },
                { id: 4, src: '../../../images/xiaomi/watch&bud/Redmi Buds 6.webp', title: 'Redmi Buds 6', desc: '旗舰双单元架构 | 49dB深度降噪 | 42h超长续航', price: '199元起' },
                { id: 5, src: '../../../images/xiaomi/watch&bud/Xiaomi Buds 5.webp', title: 'Xiaomi Buds 5', desc: '舒适无感佩戴|高通全链路无损音频|哈曼 AudioEFX 联合调音', price: '679元起' },
                { id: 6, src: '../../../images/xiaomi/watch&bud/Redmi Buds 6S.webp', title: 'Redmi Buds 6S', desc: '14.2mm超大动圈单元 | 半入耳主动降噪 | 33小时超长续航', price: '199元起' },
                { id: 7, src: '../../../images/xiaomi/watch&bud/Redmi Buds 6 活力版.webp', title: 'Redmi Buds 6 活力版', desc: '14.2mm超大动圈 | 内置五种调音模式 | 30小时长续航', price: '99元起' },
            ],
            itemListPad: [
                { id: 1, src: '../../../images/xiaomi/pad&book/Redmi Book Pro 14 2024.webp', title: 'Redmi Book Pro 14 2024', desc: '65W 满血性能|全新酷睿 Ultra 处理器', price: '4899元起' },
                { id: 2, src: '../../../images/xiaomi/pad&book/Redmi Book Pro 16 2024.webp', title: 'Redmi Book Pro 16 2024', desc: '70W 狂暴性能|3.1K 165Hz 高刷高亮屏', price: '6399元起' },
                { id: 3, src: '../../../images/xiaomi/pad&book/Redmi Book 16 2024.webp', title: 'Redmi Book 16 2024', desc: '47W 满血性能 | 小米澎湃智联 | 旗舰硬核品质', price: '3699元起' },
                { id: 4, src: '../../../images/xiaomi/pad&book/Redmi Book 14 2024.webp', title: 'Redmi Book 14 2024', desc: '47W 满血性能 | 小米澎湃智联 | 旗舰硬核品质', price: '4499元起' },
                { id: 5, src: '../../../images/xiaomi/pad&book/Redmi Pad Pro系列.webp', title: 'Redmi Pad Pro系列', desc: '12.1英寸2.5K旗舰机大屏 | 10000mAh超大电池', price: '1499元起' },
                { id: 6, src: '../../../images/xiaomi/pad&book/Xiaomi Pad 6S Pro 12.4.webp', title: 'Xiaomi Pad 6S Pro 12.4', desc: '第二代骁龙8 旗舰处理器 | 小米澎湃OS', price: '2799元起' },
                { id: 7, src: '../../../images/xiaomi/pad&book/Redmi Pad SE.webp', title: 'Redmi Pad SE', desc: '高性价比千元平板|11英寸高刷护眼大屏|全金属一体机身|73.2天超长待机', price: '849元起' },
            ],
            itemListElec: [
                { id: 1, src: '../../../images/xiaomi/elec/小米电视S系列.webp', title: '小米电视S系列', desc: '144HZ超高刷  3+32G   多色温色彩还原技术', price: '2599元起' },
                { id: 2, src: '../../../images/xiaomi/elec/小米电视S Pro Mini LED系列.webp', title: '小米电视S Pro Mini LED系列', desc: '144Hz超高刷、4+64G大存储', price: '4999元起' },
                { id: 3, src: '../../../images/xiaomi/elec/小米电视 S Mini LED 系列.webp', title: '小米电视 S Mini LED 系列', desc: 'Mini LED 高分区背光、1200nits峰值亮度', price: '2999元起' },
                { id: 4, src: '../../../images/xiaomi/elec/巨省电 小米空调 1.5匹新1级能效.webp', title: '巨省电 小米空调 1.5匹新1级能效', desc: '强劲制冷 | 高效节能 | 智能互联', price: '1899元' },
                { id: 5, src: '../../../images/xiaomi/elec/米家新风空调 立式3匹.webp', title: '米家新风空调 立式3匹', desc: '全屋快通风,就要大新风', price: '6799元' },
                { id: 6, src: '../../../images/xiaomi/elec/米家分区洗烘一体机 15kg.webp', title: '米家分区洗烘一体机 15kg', desc: '健康分开洗  一台就够了', price: '5499元' },
                { id: 7, src: '../../../images/xiaomi/elec/米家波轮洗衣机 10kg.webp', title: '米家波轮洗衣机 10kg', desc: '全景玻璃阻尼上盖 防夹手', price: '999元' },
            ],
            itemListCleaner: [
                { id: 1, src: '../../../images/xiaomi/cleaner/米家智能直流变频落地扇1X 升级版.webp', title: '米家智能直流变频落地扇1X 升级版', desc: '静音舒适自然风,支持充电宝供电,随处可用, 小爱语音控制', price: '299元' },
                { id: 2, src: '../../../images/xiaomi/cleaner/米家循环扇.webp', title: '米家循环扇', desc: '风量强劲,广域覆盖', price: '319元' },
                { id: 3, src: '../../../images/xiaomi/cleaner/米家直流变频落地扇 Pro.webp', title: '米家直流变频落地扇 Pro', desc: '收纳有序,与自然风同行', price: '399元' },
                { id: 4, src: '../../../images/xiaomi/cleaner/米家落地扇.webp', title: '米家落地扇', desc: '静享智能轻风', price: '219元' },
                { id: 5, src: '../../../images/xiaomi/cleaner/米家智能直流变频循环扇 落地式.webp', title: '米家智能直流变频循环扇 落地式', desc: '智能温湿度控风,超广域空气循环', price: '429元' },
                { id: 6, src: '../../../images/xiaomi/cleaner/米家智能直流变频塔扇2.webp', title: '米家智能直流变频塔扇2', desc: 'DIY自然风 ,环抱式柔和送风 ,儿童安全防护', price: '329元' },
                { id: 7, src: '../../../images/xiaomi/cleaner/米家桌面移动风扇.webp', title: '米家桌面移动风扇', desc: '无线长续航,随处享清凉', price: '129元' },
            ],
            itemListKitchen: [
                { id: 1, src: '../../../images/xiaomi/kitchen/米家智能燃气灶S2.webp', title: '米家智能燃气灶S2 5200W/4800W', desc: '5200W/4800W猛火 | 双环聚能火焰 | 可调节', price: '699元' },
                { id: 2, src: '../../../images/xiaomi/kitchen/米家智能定时灶S2.webp', title: '米家智能定时灶S2 5200W /4800W', desc: '5200W/4800W爆炒大火才够味 | 68%超高热效', price: '1099元' },
                { id: 3, src: '../../../images/xiaomi/kitchen/米家智能平嵌侧吸油烟机S1.webp', title: '米家智能平嵌侧吸油烟机S1', desc: '小巧机身 | 25立方大吸力 | 烟灶联动', price: '1799元' },
                { id: 4, src: '../../../images/xiaomi/kitchen/米家智能顶侧双吸油烟机S2.webp', title: '米家智能顶侧双吸油烟机S2', desc: '25m³/min大风量 | 1000Pa大静压', price: '2099元' },
                { id: 5, src: '../../../images/xiaomi/kitchen/米家智能欧式烟机S2.webp', title: '米家智能欧式烟机S2', desc: '23m³/min大吸力|500pa静压|智能干洗', price: '1499元' },
                { id: 6, src: '../../../images/xiaomi/kitchen/米家智能净烟机S2 白色.webp', title: '米家智能净烟机S2 白色', desc: '下厨不留味|无油网免拆洗|真白不惧黄', price: '2699元' },
                { id: 7, src: '../../../images/xiaomi/kitchen/米家智能净烟机P1.webp', title: '米家智能净烟机P1', desc: '高速气旋强锁烟, 劲速气流高效净吸,无油网设计免拆洗', price: '2999元' },
            ],
            itemListSmart: [
                { id: 1, src: '../../../images/xiaomi/smart/Xiaomi智能家庭屏 10.webp', title: 'Xiaomi智能家庭屏 10', desc: 'MIUI Home|10.1" 高清大屏|115°超广角摄像头|儿童模式|家庭 KTV|小爱同学', price: '899元' },
                { id: 2, src: '../../../images/xiaomi/smart/小米小爱音箱Play 增强版.webp', title: '小米小爱音箱Play 增强版', desc: 'LED时钟显示,语音控制传统家电', price: '129元' },
                { id: 3, src: '../../../images/xiaomi/smart/小米小爱音箱 Play.webp', title: '小米小爱音箱 Play', desc: '听音乐、语音遥控家电', price: '99元' },
                { id: 4, src: '../../../images/xiaomi/smart/小米小爱音箱 Pro.webp', title: '小米小爱音箱 Pro', desc: '澎湃低音,语音遥控传统家电', price: '269元' },
                { id: 5, src: '../../../images/xiaomi/smart/小米AI音箱(第二代).webp', title: '小米AI音箱(第二代)', desc: '低频饱满有深度,人声清晰有细节', price: '179元' },
                { id: 6, src: '../../../images/xiaomi/smart/小米小爱音箱.webp', title: '小米小爱音箱', desc: 'Hi-Fi级音频芯片,支持AUX IN接口,你桌面的有源音箱', price: '199元' },
                { id: 7, src: '../../../images/xiaomi/smart/Redmi小爱触屏音箱 8英寸.webp', title: 'Redmi小爱触屏音箱 8英寸', desc: '8英寸高清大屏,海量优质影音资源', price: '349元' },
            ],
        }
    }
}
</script>

<style scoped>
main {
    height: 5194px;
    width: 100%;
    background-color: rgb(245, 245, 245);
}

.container {
    width: 1226px;
    margin: 0 auto;
}

.home-banner-box {
    padding: 22px 0;
}

.home-banner-box img {
    width: 1226px;
}

.tab-list {
    height: 58px;
    padding: 14px 0;
    box-sizing: border-box;
}

.tab-list li {
    list-style: none;
    float: left;
    margin-left: 30px;
    height: 30px;
    line-height: 30px;
    cursor: pointer;
}


.tab-list .active {
    border-bottom: 2px solid rgb(255, 103, 0);
    color: rgb(255, 103, 0);
}
</style>
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
<template>
    <div class="container">
        <div class="footer-services">
            <ul>
                <li>
                    <a href="">
                        <svg t="1745810757451" class="icon tool" viewBox="0 0 1024 1024" version="1.1"
                            xmlns="http://www.w3.org/2000/svg" p-id="15017" width="24" height="24">
                            <path
                                d="M373.91591769 722.85439369c-19.74602377 0-39.49204754-1.65700898-59.23807131-5.10911106-70.00862973-12.15139925-133.66539167-45.15349491-184.0660817-95.55418494-51.09111045-51.09111045-84.23129021-115.57637689-95.96843721-186.5515952-11.46097883-69.4562934-1.79509307-139.7410913 28.1691528-203.12168507l12.56565148-26.65022789L287.61336625 418.10282403l124.8280104-124.8280104-212.2352345-212.37331858 26.65022789-12.5656515c63.38059378-29.96424587 133.66539167-39.63013162 203.12168507-28.16915279 70.97521831 11.737147 135.59856882 44.87732675 186.5515952 95.96843721 50.40069004 50.40069004 83.40278572 114.05745199 95.55418494 184.06608172 11.87523108 68.48970482 3.0378498 137.94599822-25.54555522 200.91233974l-37.69695446-17.1224262c51.64344678-113.9193679 26.92639605-250.07027305-61.58550071-338.58216981-82.85044939-82.85044939-206.15953488-109.77684543-314.96979174-71.1133024l198.70299443 198.70299445-183.3756613 183.65182946-198.84107852-198.84107851c-38.66354305 108.81025686-11.737147 232.11934237 71.1133024 314.96979173 88.51189675 88.51189675 224.52471783 113.22894749 338.58216981 61.58550071l17.12242619 37.69695446c-44.87732675 20.43644418-92.9305874 30.79275037-141.67426844 30.79275037z"
                                p-id="15018" fill="#616161">
                            </path>
                            <path
                                d="M813.989888 980.65737535c-17.81284661 0-35.62569324-6.76612003-49.1579333-20.2983601L492.3920603 687.91912086c-8.14696086-8.14696086-8.14696086-21.26494868 0-29.27382545 8.14696086-8.14696086 21.26494868-8.14696086 29.27382546 0l272.43989439 272.43989438c10.90864251 10.90864251 28.72148912 10.90864251 39.63013162 0l91.68783065-91.68783065c5.24719513-5.24719513 8.14696086-12.28948332 8.14696084-19.88410784 0-7.45654045-2.89976573-14.49882864-8.14696084-19.88410787L653.12193212 527.32733314c-8.14696086-8.14696086-8.14696086-21.26494868 0-29.27382544 8.14696086-8.14696086 21.26494868-8.14696086 29.27382545 0l272.43989438 272.43989438c13.11798782 13.11798782 20.2983601 30.5165822 20.2983601 49.15793329s-7.18037229 36.03994548-20.2983601 49.15793331l-91.68783065 91.68783064c-13.67032415 13.39415599-31.34508668 20.16027601-49.1579333 20.16027603z"
                                p-id="15019" fill="#616161">
                            </path>
                        </svg>
                        预约维修服务
                    </a>
                </li>
                <li>
                    <a href="">
                        <svg t="1745810998229" class="icon circle-7" viewBox="0 0 1024 1024" version="1.1"
                            xmlns="http://www.w3.org/2000/svg" p-id="17244" width="30" height="30">
                            <!-- <path d="M952.46 31.5H31.5v961h961v-961h-40.04z m0 920.96H71.54V71.54h880.915l0.005 880.92z"
                            p-id="17245" fill="#616161">
                        </path> -->
                            <path
                                d="M512 872.375c188.197 0 340.353-152.16 340.353-340.353S700.198 191.664 512 191.664h-60.063L512 131.601h-60.063l-80.085 80.085 80.085 80.085H512l-60.063-60.062H512c166.172 0 300.313 134.141 300.313 300.313S678.172 832.335 512 832.335 211.687 698.194 211.687 532.022h-40.04c0 188.192 152.155 340.353 340.353 340.353z"
                                p-id="17246" fill="#616161">
                            </path>
                            <path
                                d="M450.319 720.834l45.638 0.13L631.544 414.53v-53.834H390.761v41.89h200.695l-141.137 318.25z"
                                p-id="17247" fill="#616161">
                            </path>
                        </svg>
                        7天无理由退货
                    </a>
                </li>
                <li>
                    <a href="">
                        <svg t="1745811204525" class="icon circle-15" viewBox="0 0 1024 1024" version="1.1"
                            xmlns="http://www.w3.org/2000/svg" p-id="18507" width="24" height="24">
                            <path
                                d="M511.00672 1003.52c247.75168 0 448.07168-200.30976 448.07168-448.07168 0-247.75168-200.32-448.06656-448.07168-448.06656H431.93344L511.00672 28.3136H431.93344L326.50752 133.74464l105.43104 105.43104h79.06816L431.93344 160.10752h79.06816c218.76736 0 395.35104 176.59392 395.35104 395.35104 0 218.76736-176.58368 395.35616-395.35104 395.35616-218.76224 0-395.35104-176.5888-395.35104-395.35616H62.94016c0 247.75168 200.30976 448.06144 448.06656 448.06144z"
                                p-id="18508" fill="#616161">
                            </path>
                            <path
                                d="M430.52544 739.95264h-50.07872V344.6016h-105.4208V397.312h52.7104v342.64064H272.384v52.70528h158.14144v-52.70528zM630.84032 739.95264H485.87264v52.70528h144.96256c79.06816 0 144.96256-65.88416 144.96256-144.95744s-65.88928-144.96256-144.96256-144.96256h-92.25728v-105.4208h210.86208V344.6016H485.87264v210.85184h144.96256c50.0736 0 92.25728 42.17856 92.25728 92.25728s-42.17856 92.24192-92.25216 92.24192z"
                                p-id="18509" fill="#616161">
                            </path>
                        </svg>
                        15天免费换货
                    </a>
                </li>
                <li>
                    <a href="">
                        <svg t="1745811426127" class="icon gift" viewBox="0 0 1024 1024" version="1.1"
                            xmlns="http://www.w3.org/2000/svg" p-id="21679" width="24" height="24">
                            <path d="M195.58025 514.67721875l52.87528125 0 0 419.76984375-52.87528125 0 0-419.76984375Z"
                                p-id="21680" fill="#616161">
                            </path>
                            <path
                                d="M775.5183125 514.67721875l52.87528125 0 0 419.76984375-52.87528125 0 0-419.76984375Z"
                                p-id="21681" fill="#616161">
                            </path>
                            <path d="M143.26775 354.363875l52.3125 0 0 210.9375-52.3125 0 0-210.9375Z" p-id="21682"
                                fill="#616161">
                            </path>
                            <path d="M828.39359375 354.363875l52.3125 0 0 210.9375-52.3125 0 0-210.9375Z" p-id="21683"
                                fill="#616161">
                            </path>
                            <path d="M143.26775 353.8019375l737.4375 0 0 52.3125-737.4375 0 0-52.3125Z" p-id="21684"
                                fill="#616161">
                            </path>
                            <path
                                d="M172.51803125 511.86415625l657.00028125 0 0 53.43721875-657.00028125 0 0-53.43721875Z"
                                p-id="21685" fill="#616161">
                            </path>
                            <path d="M205.141625 881.009l591.75225 0 0 53.4380625-591.75225 0 0-53.4380625Z"
                                p-id="21686" fill="#616161">
                            </path>
                            <path
                                d="M458.97115625 385.3008125l105.0485625 0 0 520.87471875-105.0485625 0 0-520.87471875Z"
                                p-id="21687" fill="#616161">
                            </path>
                            <path
                                d="M523.1931875 354.40353125C518.73734375 125.9725625 343.40103125 30.28203125 269.13584375 129.761 180.1784375 248.9204375 357.58025 357.73971875 357.58025 357.73971875s4.9528125 11.39990625 60.4546875 19.86440625C450.07128125 382.49028125 524.82415625 438.00228125 523.1931875 354.40353125zM448.14246875 355.4894375c-36.56221875 0-91.843875-45.98859375-91.843875-45.98859375s-73.98253125-75.57215625-39.77015625-129.28865625c31.48875-49.44121875 146.1661875-4.13690625 148.74890625 128.25421875C466.2231875 356.9170625 466.9251875 355.4894375 448.14246875 355.4894375z"
                                p-id="21688" fill="#616161">
                            </path>
                            <path
                                d="M601.90325 377.604125c55.501875-8.46534375 60.4546875-19.86440625 60.4546875-19.86440625s183.9324375-105.2780625 86.4405-226.96875C671.18103125 33.8856875 501.20253125 125.9725625 496.74584375 354.40353125 495.114875 438.00228125 569.86775 382.49028125 601.90325 377.604125zM554.66084375 308.46640625C557.24440625 176.0744375 673.8936875 133.18240625 703.41059375 180.21134375c33.5761875 53.49628125-39.77015625 129.28865625-39.77015625 129.28865625s-55.2825 45.98859375-91.84471875 45.98859375C553.01384375 355.4894375 553.71584375 356.9170625 554.66084375 308.46640625z"
                                p-id="21689" fill="#616161">
                            </path>
                        </svg>
                        满69包邮
                    </a>
                </li>
                <li>
                    <a href="">
                        <svg t="1745811515464" class="icon location" viewBox="0 0 1024 1024" version="1.1"
                            xmlns="http://www.w3.org/2000/svg" p-id="22794" width="24" height="24">
                            <path
                                d="M503.23456 885.82144l-14.04928-14.15168C478.02368 860.38528 215.49056 593.92 215.49056 434.7904c0-163.55328 129.29024-296.61184 288.21504-296.61184 158.90432 0 288.21504 132.28032 288.256 294.87104 0.04096 159.0272-271.4624 436.51072-274.20672 439.07072l-14.52032 13.70112z m0.49152-706.6624c-136.33536 0-247.25504 114.688-247.25504 255.65184 0 122.79808 192.7168 335.21664 247.48032 393.09312C563.2 765.62432 751.06304 549.4784 751.02208 433.07008c-0.04096-140.00128-110.98112-253.91104-247.296-253.91104z m1.88416 360.83712c-68.9152 0-125.00992-57.79456-125.00992-128.83968s56.07424-128.8192 125.00992-128.8192c68.89472 0 124.96896 57.79456 124.96896 128.8192s-56.05376 128.83968-124.96896 128.83968z m0-216.6784c-46.34624 0-84.04992 39.40352-84.04992 87.8592s37.70368 87.8592 84.04992 87.8592c46.32576 0 84.00896-39.40352 84.00896-87.8592s-37.6832-87.8592-84.00896-87.8592z"
                                fill="#616161" p-id="22795">
                            </path>
                        </svg>
                        1100余家售后网点
                    </a>
                </li>
            </ul>
        </div>
        <div class="footer-links">
            <dl v-for="item1 in linkList">
                <dt>{{ item1.title }}</dt>
                <dd v-for="item2 in item1.ddList">
                    <a href="javascript:;">{{ item2 }}</a>
                </dd>
            </dl>
            <div class="right-contact">
                <div class="col-contact">
                    <p class="phone">950816</p>
                    <p class="time">8:00-18:00仅收市话费</p>
                    <a class="btn">
                        <svg t="1745977646738" class="icon" viewBox="0 0 1024 1024" version="1.1"
                            xmlns="http://www.w3.org/2000/svg" p-id="2668" width="16" height="16">
                            <path
                                d="M851.6096 136.8064H168.448c-44.0832 0-79.872 35.7376-79.872 79.872v479.1808c0 44.0832 35.7376 79.872 79.872 79.872h95.6928l0.8704 105.5232c0.1536 15.5648 16.7424 25.4464 30.5152 18.176l232.704-123.6992h323.3792c44.0832 0 79.872-35.7376 79.872-79.872v-479.232c0-44.0832-35.7376-79.8208-79.872-79.8208z m-287.3856 453.6832H296.192c-23.9616 0-43.3664-19.4048-43.3664-43.3664s19.4048-43.3664 43.3664-43.3664h268.032c23.9616 0 43.3664 19.4048 43.3664 43.3664s-19.4048 43.3664-43.3664 43.3664z m168.3968-175.5136H296.192c-23.9616 0-43.3664-19.4048-43.3664-43.3664s19.4048-43.3664 43.3664-43.3664h436.48c23.9616 0 43.3664 19.4048 43.3664 43.3664s-19.456 43.3664-43.4176 43.3664z"
                                fill="#FC7032" p-id="2669">
                            </path>
                            <path
                                d="M931.4816 216.6272c0-44.0832-35.7376-79.872-79.872-79.872H168.448c-44.0832 0-79.872 35.7376-79.872 79.872v479.1808c0 44.0832 35.7376 79.872 79.872 79.872h95.6928l0.256 31.8976c25.088 3.072 50.5856 4.8128 76.544 4.8128 53.3504 0 105.0624-6.7072 154.3168-19.2l32.9728-17.5104h24.3712c190.6688-68.5568 335.5648-227.072 378.88-421.7856V216.6272z m-367.2576 373.8624H296.192c-23.9616 0-43.3664-19.4048-43.3664-43.3664 0-23.9616 19.4048-43.3664 43.3664-43.3664h268.032c23.9616 0 43.3664 19.4048 43.3664 43.3664 0 23.9616-19.4048 43.3664-43.3664 43.3664z m168.3968-175.5136H296.192c-23.9616 0-43.3664-19.4048-43.3664-43.3664 0-23.9616 19.4048-43.3664 43.3664-43.3664h436.48c23.9616 0 43.3664 19.4048 43.3664 43.3664-0.0512 23.9616-19.456 43.3664-43.4176 43.3664z"
                                fill="#FF7E3E" p-id="2670">
                            </path>
                            <path
                                d="M88.6272 216.6272v383.5392c28.4672 3.9424 57.4976 6.0928 87.0912 6.0928 48.0768 0 94.7712-5.5808 139.6224-15.7696h-19.2c-23.9616 0-43.3664-19.4048-43.3664-43.3664 0-23.9616 19.4048-43.3664 43.3664-43.3664h222.1568c38.656-25.6512 74.0864-55.4496 105.5232-88.832h-327.68c-23.9616 0-43.3664-19.4048-43.3664-43.3664 0-23.9616 19.4048-43.3664 43.3664-43.3664h395.1616c36.864-57.9072 63.3856-122.5216 77.2608-191.488H168.448c-44.0832 0.1024-79.8208 35.84-79.8208 79.9232z"
                                fill="#FF9552" p-id="2671">
                            </path>
                            <path
                                d="M88.6272 216.6272v180.8896c58.5728-5.9904 114.5856-20.0704 166.9632-40.96 6.144-16.4864 21.9648-28.2624 40.6016-28.2624h20.1728c86.528-46.1312 159.9488-112.0768 213.76-191.488H168.448c-44.0832 0-79.8208 35.7376-79.8208 79.8208z"
                                fill="#FFA56A" p-id="2672">
                            </path>
                        </svg>
                        人工客服
                    </a>
                </div>
                <p class="phone" style="margin-top: 25px;">950818</p>
                <div style="width: 200px; text-align: left; margin-left: 52px;">
                    <p class="time">8:00-18:00仅收市话费</p>
                    <p class="notice">手机适用于Xiaomi MIX Fold系列MIX Flip系列数字12系列及以上</p>
                    <p class="notice">电视适用于98100寸电视</p>
                </div>
                <a class="btn">
                    <svg t="1745977646738" class="icon" viewBox="0 0 1024 1024" version="1.1"
                        xmlns="http://www.w3.org/2000/svg" p-id="2668" width="16" height="16">
                        <path
                            d="M851.6096 136.8064H168.448c-44.0832 0-79.872 35.7376-79.872 79.872v479.1808c0 44.0832 35.7376 79.872 79.872 79.872h95.6928l0.8704 105.5232c0.1536 15.5648 16.7424 25.4464 30.5152 18.176l232.704-123.6992h323.3792c44.0832 0 79.872-35.7376 79.872-79.872v-479.232c0-44.0832-35.7376-79.8208-79.872-79.8208z m-287.3856 453.6832H296.192c-23.9616 0-43.3664-19.4048-43.3664-43.3664s19.4048-43.3664 43.3664-43.3664h268.032c23.9616 0 43.3664 19.4048 43.3664 43.3664s-19.4048 43.3664-43.3664 43.3664z m168.3968-175.5136H296.192c-23.9616 0-43.3664-19.4048-43.3664-43.3664s19.4048-43.3664 43.3664-43.3664h436.48c23.9616 0 43.3664 19.4048 43.3664 43.3664s-19.456 43.3664-43.4176 43.3664z"
                            fill="#FC7032" p-id="2669">
                        </path>
                        <path
                            d="M931.4816 216.6272c0-44.0832-35.7376-79.872-79.872-79.872H168.448c-44.0832 0-79.872 35.7376-79.872 79.872v479.1808c0 44.0832 35.7376 79.872 79.872 79.872h95.6928l0.256 31.8976c25.088 3.072 50.5856 4.8128 76.544 4.8128 53.3504 0 105.0624-6.7072 154.3168-19.2l32.9728-17.5104h24.3712c190.6688-68.5568 335.5648-227.072 378.88-421.7856V216.6272z m-367.2576 373.8624H296.192c-23.9616 0-43.3664-19.4048-43.3664-43.3664 0-23.9616 19.4048-43.3664 43.3664-43.3664h268.032c23.9616 0 43.3664 19.4048 43.3664 43.3664 0 23.9616-19.4048 43.3664-43.3664 43.3664z m168.3968-175.5136H296.192c-23.9616 0-43.3664-19.4048-43.3664-43.3664 0-23.9616 19.4048-43.3664 43.3664-43.3664h436.48c23.9616 0 43.3664 19.4048 43.3664 43.3664-0.0512 23.9616-19.456 43.3664-43.4176 43.3664z"
                            fill="#FF7E3E" p-id="2670">
                        </path>
                        <path
                            d="M88.6272 216.6272v383.5392c28.4672 3.9424 57.4976 6.0928 87.0912 6.0928 48.0768 0 94.7712-5.5808 139.6224-15.7696h-19.2c-23.9616 0-43.3664-19.4048-43.3664-43.3664 0-23.9616 19.4048-43.3664 43.3664-43.3664h222.1568c38.656-25.6512 74.0864-55.4496 105.5232-88.832h-327.68c-23.9616 0-43.3664-19.4048-43.3664-43.3664 0-23.9616 19.4048-43.3664 43.3664-43.3664h395.1616c36.864-57.9072 63.3856-122.5216 77.2608-191.488H168.448c-44.0832 0.1024-79.8208 35.84-79.8208 79.9232z"
                            fill="#FF9552" p-id="2671">
                        </path>
                        <path
                            d="M88.6272 216.6272v180.8896c58.5728-5.9904 114.5856-20.0704 166.9632-40.96 6.144-16.4864 21.9648-28.2624 40.6016-28.2624h20.1728c86.528-46.1312 159.9488-112.0768 213.76-191.488H168.448c-44.0832 0-79.8208 35.7376-79.8208 79.8208z"
                            fill="#FFA56A" p-id="2672">
                        </path>
                    </svg>
                    人工客服
                </a>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            linkList: [
                {
                    title: '',
                    ddList: []
                },
                {
                    title: '选购指南',
                    ddList: ['手机', '电视', '笔记本', '平板', '穿戴', '耳机', '家电', '路由器', '音箱', '配件']
                },
                {
                    title: '服务中心',
                    ddList: ['申请售后', '售后政策', '维修服务价格', '订单查询', '以旧换新', '保障服务', '防伪查询', 'F码通道']
                },
                {
                    title: '线下门店',
                    ddList: ['小米之家', '服务网点', '授权体验店/专区']
                },

                {
                    title: '关于小米',
                    ddList: ['了解小米', '加入小米', '投资者关系', '可持续发展', '廉洁举报']
                },
                {
                    title: '关注我们',
                    ddList: ['新浪微博', '官方微信', '联系我们', '公益基金会']
                },
            ]
        }
    }
}
</script>

<style>
.container {
    width: 1226px;
    margin: 0 auto;
}

.container .footer-services {
    border-bottom: 1px solid rgb(224, 224, 224);
}

.container .footer-services ul {
    padding: 27px 0;
    /* display: flex; */
    /* justify-content: space-around; */
    height: 79px;
    box-sizing: border-box;
}

.container .footer-services li {
    list-style: none;
    height: 25px;
    color: rgb(97, 97, 97);
    line-height: 25px;
    cursor: pointer;
    border-left: 1px solid rgb(224, 224, 224);
    width: 243px;
    text-align: center;
    float: left;
    line-height: 25px;
}

.container .footer-services li:first-child {
    border: 0;
}

.container .footer-services li svg {
    float: left;
    position: relative;
}

.container .footer-services li svg.tool {
    left: 56px;
    top: 0;
}

.container .footer-services li svg.circle-7 {
    left: 50px;
    top: -3px;
}

.container .footer-services li svg.circle-15 {
    left: 54px;
    top: 0;
}

.container .footer-services li svg.gift {
    left: 70px;
    top: 0;
}

.container .footer-services li svg.location {
    left: 40px;
    top: 0;
}

.container .footer-services li a {
    height: 25px;
    line-height: 25px;
    color: rgb(97, 97, 97);
    text-decoration: none;
}

.container .footer-links {
    height: 392.5px;
    box-sizing: border-box;
    padding: 40px 0;
}

.footer-links dl {
    width: 160px;
    height: 25px;
    float: left;
}

.footer-links dl dt {
    height: 17.5px;
    line-height: 17.5px;
    font-size: 14px;
    margin-top: -1px;
    margin-bottom: 26px;
    color: rgb(66, 66, 66);
}

.footer-links dl dd {
    color: rgb(117, 117, 117);
    font-size: 12px;
    margin-top: 10px;
    line-height: 18px;
    /* cursor: pointer; */
}

.footer-links dl dd a {
    color: rgb(117, 117, 117);
    text-decoration: none;
}

.footer-links dl dd a:hover {
    color: rgb(255, 103, 0);
}

.footer-links .right-contact {
    width: 251px;
    float: right;
    text-align: center;
}

.footer-links .right-contact .col-contact {
    width: 251px;
    height: 80px;
    border-left: 1px solid rgb(224, 224, 224);
}

.right-contact .phone {
    height: 22px;
    margin-bottom: 5px;
    color: rgb(255, 103, 0);
    font-size: 22px;
    line-height: 22px;
}

.right-contact .time {
    font-size: 12px;
    color: rgb(97, 97, 97);
    height: 18px;
    line-height: 18px;
    margin-bottom: 5px;
}

.right-contact .btn {
    width: 120px;
    height: 30px;
    border: 1px solid rgb(255, 103, 0);
    display: inline-block;
    font-size: 12px;
    line-height: 30px;
    color: #FF6700;
}

.right-contact .notice {
    font-size: 12px;
    color: rgb(97, 97, 97);
    /* height: 18px; */
    line-height: 18px;
    margin-bottom: 5px;
    margin-top: 3px;
}
</style>

App

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
    <Header />
    <Tab />
    <Wrapper />
    <Main></Main>
    <Footer></Footer>
</template>

<script>
import Main from '@/components/xiaomi/Main.vue';
import Header from '@/components/xiaomi/Header.vue';
import Tab from '@/components/xiaomi/Tab.vue';
import Wrapper from '@/components/xiaomi/Wrapper.vue';
import Footer from './components/xiaomi/Footer.vue';

export default {
    components: {
        Header,
        Tab,
        Wrapper,
        Main,
        Footer,
    }
}
</script>
Blog for Sandy Memories