Featured image of post 第四章 组件基础(下)

第四章 组件基础(下)

Vue 生命周期

生命周期的四个阶段

Vue 生命周期:一个 Vue 实例从创建销毁的整个过程。

组件每个阶段它的内部构造是不一样的,所以一般特定的钩子做特定的事,比如 Ajax 获取数据就可以在 mounted 阶段。

从 Vue 实例被创建开始到该实例最终被销毁的整个过程叫做 VUE 的生命周期,在这个生命周期内发生了下面的事情:从 vue 实例被创建开始,首先 vue 实例被创建,之后开始数据的初始化,编译模板,挂载 dom,渲染 dom,更新对象属性,渲染 dom,解绑销毁。

创建:const app = new Vue({ ... })

销毁:关闭页面

生命周期四个阶段:①创建 ②挂载 ③更新 ④销毁

生命周期钩子函数

Vue 生命周期过程中,会自动运行一些函数,被称为生命周期钩子,让开发者可以在特定阶段运行自己的代码。

 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
<template>
  <p>{{ m1 }}</p>
  <button @click="change">修改</button>
</template>

<script>
export default {
  data() {
    return {
      m1: 111
    }
  },
  beforeCreate() {
    console.log('beforeCreate 响应式数据创建前', this.m1);
  },
  created() {
    console.log('created 响应式数据创建后', this.m1);
  },
  beforeMount() {
    console.log('beforeMount 模板渲染前', document.querySelector('p'));
  },
  mounted() {
    console.log('mounted 模板渲染后', document.querySelector('p'));
  },
  beforeUpdate() {
    console.log('beforeUpdate 数据修改视图未更新');
  },
  updated() {
    console.log('updated 数据修改视图已更新');
  },
  beforeDestroy() {
    console.log('beforeDestroy 卸载前');
  },
  destroyed() {
    console.log('destroyed 卸载后');
  },
  methods: {
    change() {
      this.m1 = 222;
    }
  }
}
</script>

<style></style>

自定义指令

基础语法

自定义指令 — Vue.js (vuejs.org)

自定义指令:自己定义的指令,可以封装一些 dom 操作,扩展额外功能。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 局部注册
directives: {
  自定义指令名: {
    钩子函数: function (参数) {
      执行内容
    }
  },
  自定义指令名: function (参数) {
      执行内容
  }
}

// 全局注册
Vue.directive('自定义指令名', {
  钩子函数: function (参数) {
    执行内容
  }
})

// 自定义函数的使用
<标签名 v-自定义指令名 />

自定义指令钩子函数

钩子函数 描述
bind 只调用一次,在指令第一次绑定到元素时触发。可以在这里进行初始设置、绑定事件监听器等操作。
inserted 在被绑定元素插入父节点时触发。如果指令绑定的元素是动态生成的,在插入后才会触发。
update 在指令所在模板更新时触发,不论绑定值是否发生变化。可以通过比较更新前后的绑定值,以便在需要时执行相应的操作。
componentUpdated 在被绑定元素所在模板完成一次更新周期时触发。如果需要在每次更新时执行操作,可以选择使用这个钩子函数。
unbind 只调用一次,在指令与元素解绑时触发。可以在这里进行清理工作、移除事件监听器等操作。

常用的自定义指令生命周期函数的参数:

参数 说明
el 指令所绑定的元素,可以直接用于操作 dom 元素
binding 一个对象,包含多个属性,用于接收属性的参数值
vnode 代表绑定元素底层的虚拟节点
prevNode 之前页面渲染中指令所绑定元素的虚拟节点

在 Vue3 中,自定义指令的钩子函数名称更改为:

- beforeMount:代替 bind

- mounted:代替 inserted

- beforeUpdate:新

- updated:代替 componentUpdated

- beforeUnmount:新

- unmounted:代替 unbind

钩子函数示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Vue.directive('my-directive', {
  bind: function(el, binding, vnode, oldVnode) {
    // 指令绑定时执行的操作
  },
  inserted: function(el, binding) {
    // 元素插入父节点时执行的操作
  },
  update: function(el, binding) {
    // 指令所在模板更新时执行的操作
  },
  componentUpdated: function(el, binding) {
    // 模板完成一次更新周期时执行的操作
  },
  unbind: function(el, binding) {
    // 指令与元素解绑时执行的操作
  }
})

编写代码,创建自定义指令,通过自定义指令能够让文字颜色变为红色。

  1. 使用 directives: { 方法名: { 钩子函数: function(形参){ 执行的代码}}}

  2. 在标签中使用 v-方法名 调用 Vue 指令

 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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <div v-red>使用自定义指令让这段文字变为红色</div>
        <div v-cyan>使用自定义指令让这段文字变为青色</div>
    </div>
    <script src="/MyPra/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            directives: {
                red: function (el){
                    el.style.color = 'red'
                },
                cyan: function (el){
                    el.style.color = 'cyan'
                }
            }
        })
    </script>
</body>
</html>

在 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
<template>
    <div v-test v-red v-green v-blue>{{ msg }}</div>
    <button @click="change">改变div中的文字</button>
</template>

<script>
export default {
    data(){
        return{
            msg: '测试'
        }
    },
    directives: {
        test: {
            beforeMount: function (el, binding) {
                console.log(111);
                console.log(el);
                console.log(binding);
            }
        },
        red: {
            mounted: function (el) {
                el.style.color = 'red'
            }
        },
        green: function (el) {
            el.style.color = 'green'
        },
        blue: {
            updated: function (el) {
                el.style.color = 'blue'
            }
        },
    },
    methods: {
        change() {
            this.msg = '改变后的文字'
        }
    }
};
</script>

插槽

默认插槽

作用:让组件内部的一些结构支持自定义。

封装组件后,希望组件中的部分内容能够动态修改,可以使用插槽。

  1. 组件内需要定制的结构部分,改用 <slot></slot> 占位。

  2. 使用组件时,<MyDialog></MyDialog> 标签内部,传入结构替换 slot

Video

 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>
  <div class="box">
    <!-- 1. 在需要修改的位置使用 slot 标签占位 -->
    <!-- <img src="../../img/film1.webp" alt=""> -->
    <!-- <div class="title">海王2</div> -->
    <slot></slot>
  </div>
</template>

<script>

</script>

<style>
    .box{
        width: 466px;
        float: left;
        margin: 10px;
    }
    .title{
        line-height: 50px;
        font-size: 24px;
        text-align: center;
    }
</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
<template>
  <!-- <Video /> -->
  <!-- <Video /> -->
  <Video>
    <img src="../../img/film1.webp" alt="">
    <div class="title">海王2</div>
  </Video>
  <Video>
    <img src="../../img/film2.webp" alt="">
    <div class="title">侏罗纪世界</div>
  </Video>
</template>

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

<style></style>

后背内容(默认值)

插槽后备内容:封装组件时,可以为预留的 <slot> 插槽提供后备内容(默认内容)。

语法:在 <slot> 标签内,放置内容,作为默认显示内容,如果组件标签中有内容,则默认内容不显示。

1
2
3
<slot><div class="title">...</div></slot>

<Video></Video>

具名插槽

默认插槽只能定制一个位置的内容,如果在组件中,有多个地方需要改变内容,此时需要使用具名插槽,即具有名字的插槽,通过 name 属性为插槽命名,再进行区分。

使用方法:

  • 多个 slot 使用 name 属性区分名字

  • template 配合 v-slot:name 来分发对应标签

插槽添加 name 属性后,就是具名插槽,只支持定向分发。此外,v-slot:name 可以简写为 #name

Video

 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
<template>
  <div class="box">
    <!-- <img src="../../img/film1.webp" alt=""> -->
    <slot name="img"></slot>
    <!-- <div class="title">海王2</div> -->
    <slot name="title"></slot>
  </div>
</template>

<script>

</script>

<style>
    .box{
        border: 2px solid black;
        width: 466px;
        float: left;
        margin: 10px;
    }
    .title{
        line-height: 50px;
        font-size: 24px;
        text-align: center;
    }
</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
26
27
28
29
30
31
<template>
  <!-- <Video /> -->
  <!-- <Video /> -->
  <Video>
    <template v-slot:img>
      <img src="../../img/film1.webp" alt="">
    </template>
    <template v-slot:title>
      <div class="title">海王2</div>
    </template>
  </Video>
  <Video>
    <template #img>
      <img src="../../img/film2.webp" alt="">
    </template>
    <template #title>
    <div class="title">侏罗纪世界</div>
    </template>
  </Video>
</template>

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

<style></style>

作用域插槽

作用域插槽是插槽的一个传参语法。

作用域插槽:定义 slot 插槽的同时是可以传值的。给插槽上可以绑定数据,将来使用组件时可以调用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!-- 基本使用步骤: -->

<!-- 1.  slot 标签以添加属性的方式传值 -->

<slot :id="item.id" :msg="测试文本"></slot>

<!-- 2. 所有添加的属性都会被收集到一个对象中 -->

{ id: 3 msg:'测试文本'}

<!-- 3.  template 通过 `#插槽名= "obj"` 接收默认插槽名为 default -->

<Table :list="list">
  <template #default="obj">
    <button @click="del(obj.id)">删除</button>
    </template>
</Table>

案例:表格业务动态变化

插槽渲染的不只有数据,也有可能需要动态渲染方法的时候,此时方法无法直接调用父组件中的数据,需要使用作用域插槽进行数据传递。

 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
<template>
    <table class="table">
        <thead>
            <tr>
                <th>序号</th>
                <th>手机型号</th>
                <th>价格</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>1</td>
                <td>小米</td>
                <td>6999</td>
                <td><button>修改</button></td>
            </tr>
            <tr>
                <td>2</td>
                <td>华为</td>
                <td>8866</td>
                <td><button>修改</button></td>
            </tr>
            <tr>
                <td>3</td>
                <td>苹果</td>
                <td>9998</td>
                <td><button>修改</button></td>
            </tr>
        </tbody>
    </table>

    <table class="table">
        <thead>
            <tr>
                <th>序号</th>
                <th>手机型号</th>
                <th>价格</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>1</td>
                <td>vivo</td>
                <td>6688</td>
                <td><button>删除</button></td>
            </tr>
            <tr>
                <td>2</td>
                <td>oppo</td>
                <td>5888</td>
                <td><button>删除</button></td>
            </tr>
            <tr>
                <td>3</td>
                <td>meizu</td>
                <td>4999</td>
                <td><button>删除</button></td>
            </tr>
        </tbody>
    </table>
</template>

<script>

</script>

<style>
.table {
    border-collapse: collapse;
    text-align: center;
    width: 500px;
    margin: 10px;
}

.table th,
.table td {
    border: 1px solid black;
}
</style>

需求:

① 能够根据不同数组渲染列表

② 操作分为两种:删除和修改(slot

③ 点击删除/修改时对数据进行操作,此时在父组件中无法使用 item.id 传值,需要使用作用域插槽

④ 为 slot 添加属性,在父组件中使用 template 标签和 #default="obj" 属性接收传值

将上方代码改为组件+插槽的形式:

Table

 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
<template>
    <table class="table">
        <thead>
            <tr>
                <th>序号</th>
                <th>手机型号</th>
                <th>价格</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="(item, index) in dataList" :key="item.id">
                <td>{{ index + 1 }}</td>
                <td>{{ item.type }}</td>
                <td>{{ item.price }}</td>
                <td>
                    <!-- <button>修改</button> -->
                    <slot></slot>
                </td>
            </tr>
        </tbody>
    </table>
</template>

<script>
export default {
    props: {
        dataList: Array
    }
}
</script>

<style>
.table {
    border-collapse: collapse;
    text-align: center;
    width: 500px;
    margin: 10px;
}

.table th,
.table td {
    border: 1px solid black;
}
</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
26
27
28
29
30
31
32
33
<template>
    <Table :dataList="list1">
        <button>修改</button>
    </Table>
    <Table :dataList="list2">
        <button>删除</button>
    </Table>
</template>

<script>
import Table from './components/directives&slot/table.vue'
export default {
    data() {
        return {
            list1: [
                { id: 1, type: '小米', price: 6999 },
                { id: 2, type: '华为', price: 8866 },
                { id: 3, type: '苹果', price: 9998 },
            ],
            list2: [
                { id: 1, type: 'vivo', price: 6688 },
                { id: 2, type: 'oppo', price: 5888 },
                { id: 3, type: 'meizu', price: 4999 },
            ]
        }
    },
    components: {
        Table
    }
}
</script>

<style></style>

此时尝试在 App.vue 当中为 button 添加删除逻辑,如下:

1
2
3
4
5
6
7
8
<template>
    <Table :dataList="list1">
        <button>修改</button>
    </Table>
    <Table :dataList="list2">
        <button @click="del(item.id)">删除</button>
    </Table>
</template>

Table.vue 当中添加删除方法,如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<script>
export default {
    props: {
        dataList: Array
    },
    methods: {
        del(id){
            for (let i = 0; i < this.dataList.length; i++) {
                if(id == this.dataList[i].id){
                    this.dataList.splice[i, 1]
                }
            }
        }
    }
}
</script>

显示的报错信息为:

需要在子组件的 slot 标签中使用 v-bind 绑定属性传值,vue 会将 slot 标签中传递的值保存在一个数组当中,在父组件引用的子组件标签中使用 template+v-slot:插槽名="自定义对象" 即可将子组件中所有传递的数据存储在该对象中。

此时在父组件中即可通过 自定义对象.传递数据 的方法获取到子组件的数据,从而调用方法。

Table

 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>
    <table class="table">
        <thead>
            <tr>
                <th>序号</th>
                <th>手机型号</th>
                <th>价格</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="(item, index) in dataList" :key="item.id">
                <td>{{ index + 1 }}</td>
                <td>{{ item.type }}</td>
                <td>{{ item.price }}</td>
                <td>
                    <!-- <button>修改</button> -->
                    <slot :item="item"></slot>
                </td>
            </tr>
        </tbody>
    </table>
</template>

<script>
export default {
    props: {
        dataList: Array
    },

}
</script>

<style>
.table {
    border-collapse: collapse;
    text-align: center;
    width: 500px;
    margin: 10px;
}

.table th,
.table td {
    border: 1px solid black;
}
</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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<template>
    <Table :dataList="list1">
        <button>修改</button>
    </Table>
    <Table :dataList="list2">
        <template v-slot:default="obj">
            <button @click="del(obj.item.id)">删除</button>
        </template>
    </Table>
</template>

<script>
import Table from './components/directives&slot/table.vue'
export default {
    data() {
        return {
            list1: [
                { id: 1, type: '小米', price: 6999 },
                { id: 2, type: '华为', price: 8866 },
                { id: 3, type: '苹果', price: 9998 },
            ],
            list2: [
                { id: 1, type: 'vivo', price: 6688 },
                { id: 2, type: 'oppo', price: 5888 },
                { id: 3, type: 'meizu', price: 4999 },
            ]
        }
    },
    components: {
        Table
    },
    methods: {
        del(id) {
            for (let i = 0; i < this.list2.length; i++) {
                if (id == this.list2[i].id) {
                    this.list2.splice(i, 1)
                }
            }
        }
    }
}
</script>

<style></style>

动态组件

定义动态组件

利用动态组件可以动态切换页面中显示的组件。使用 <component> 标签可以定义动态组件,<component> 标签必须配合 is 属性一起使用,is 属性的属性值表示要渲染的组件。

在 vue3 中,使用 setup 语法糖配合 shallowRef() 函数可以将组件保存为响应式数据。shallowRef() 函数只处理对象最外层属性的响应,它比 ref() 函数更适合将组件保存为响应式数据。

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
<template>
    <button @click="showComponent = Main">显示Main组件</button>
    <button @click="showComponent = Header">显示Header组件</button>
    <component :is="showComponent"></component>
</template>

<script setup>
import Main from './components/xiaomi/Main.vue';
import Header from './components/xiaomi/Header.vue';

import { shallowRef } from 'vue';

const showComponent = shallowRef(Main);
</script>

<style scoped>
button {
    width: 100px;
    height: 50px;
    margin: 30px;
    position: absolute;
    top: 20px;
}

button:first-child {
    top: 100px;
}
</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
<template>
  <div id="app" style="text-align: center;">
    <h1>Vue 中动态组件的使用</h1>
    <div v-for="item in modules" :id="item.id" style="margin: 10px 0;">
      <component :is="item.type"></component>
      <!-- <p>{{ item.type }}</p> -->
    </div>
  </div>
</template>

<script>
import Image from './components/activeComponents/Image.vue';
import Text from './components/activeComponents/Text.vue';
import Video from './components/activeComponents/Video.vue';
export default {
  data() {
    return {
      modules: [
        { id: 1, type: 'text' },
        { id: 2, type: 'video' },
        { id: 3, type: 'image' },
        { id: 4, type: 'image' },
        { id: 5, type: 'text' }
      ],
      // news: 'Image'
    }
  },
  components: {
    Image,
    Text,
    Video
  },
  // computed:{
  //   getType(){
  //     return this.modules.map(item => {
  //       return {
  //         ...item,
  //         type: 'news-' + item.type,
  //       }
  //     })
  //   }
  // }
}
</script>

实战案例

基础样式

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
<template>
    <div class="goods">
        <div class="goods-img">
            <img src="../../../img/Redmi Turbo 3.png" alt="">
        </div>
        <h3 class="title">Redmi Turbo 3</h3>
        <p class="desc">性能旋风席卷而来</p>
        <p class="price">1999元起</p>
    </div>
</template>

<style>
.goods {
    width: 240px;
    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 7px 14px 7px;
    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 0;
    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>

Part

 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
<template>
    <div class="bgc">
        <div class="main-box">
            <div class="left-img">
                <img src="../../../img/xiaomiphone.webp" alt="">
            </div>
            <div class="right-goods">
                <Goods></Goods>
                <Goods></Goods>
                <Goods></Goods>
                <Goods></Goods>
                <Goods></Goods>
                <Goods></Goods>
                <Goods></Goods>
                <Goods></Goods>
            </div>
        </div>
    </div>
</template>

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

<style>
.bgc {
    background-color: rgb(245, 245, 245);
    height: 614px;
    padding: 10px;
    user-select: none;
}

.main-box {
    width: 68%;
    margin: auto;
}

.left-img {
    float: left;
    cursor: pointer;
    margin-right: 7px;
}

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

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

App

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

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

<style></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
<template>
    <div class="goods">
        <div class="goods-img">
            <slot name="img"></slot>
        </div>
        <h3 class="title"><slot name="title"></slot></h3>
        <p class="desc"><slot name="desc"></slot></p>
        <p class="price"><slot name="price"></slot>元起</p>
    </div>
</template>


<style>
.goods {
    width: 240px;
    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 7px 14px 7px;
    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 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>

Part

  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="bgc">
        <div class="main-box">
            <div class="left-img">
                <img src="../../../img/xiaomiphone.webp" alt="">
            </div>
            <div class="right-goods">
                <Goods>
                    <template v-slot:img>
                        <img src="../../../img/Redmi Turbo 3.png" alt="">
                    </template>
                    <template v-slot:title>Redmi Turbo 3</template>
                    <template v-slot:desc>性能旋风席卷而来</template>
                    <template v-slot:price>1999</template>
                </Goods>
                <Goods>
                    <template v-slot:img>
                        <img src="../../../img/Xiaomi Civi 4 Pro.png" alt="">
                    </template>
                    <template v-slot:title>Xiaomi Civi 4 Pro</template>
                    <template v-slot:desc>徕卡光学Summilux镜头 | 5000万徕卡人像镜头</template>
                    <template v-slot:price>2999</template>
                </Goods>
                <Goods>
                    <template v-slot:img>
                        <img src="../../../img/Xiaomi 14 Ultra.png" alt="">
                    </template>
                    <template v-slot:title>Xiaomi 14 Ultra</template>
                    <template v-slot:desc>徕卡全明星四摄 | 双向卫星通信  | 小米澎湃OS</template>
                    <template v-slot:price>6499</template>
                </Goods>
                <Goods>
                    <template v-slot:img>
                        <img src="../../../img/Redmi K70 Pro.jpg" alt="">
                    </template>
                    <template v-slot:title>Redmi K70 Pro</template>
                    <template v-slot:desc>第三代骁龙8 年度旗舰平台</template>
                    <template v-slot:price>3299</template>
                </Goods>
                <Goods>
                    <template v-slot:img>
                        <img src="../../../img/Redmi K70.png" alt="">
                    </template>
                    <template v-slot:title>Redmi K70</template>
                    <template v-slot:desc>第二代骁龙8 旗舰芯</template>
                    <template v-slot:price>2399</template>
                </Goods>
                <Goods>
                    <template v-slot:img>
                        <img src="../../../img/Redmi K70E.png" alt="">
                    </template>
                    <template v-slot:title>Redmi K70E</template>
                    <template v-slot:desc>新一代旗舰焊门员</template>
                    <template v-slot:price>1799</template>
                </Goods>
                <Goods>
                    <template v-slot:img>
                        <img src="../../../img/Xiaomi 14 Pro.png" alt="">
                    </template>
                    <template v-slot:title>Xiaomi 14 Pro</template>
                    <template v-slot:desc>徕卡Summilux可变光圈镜头小米澎湃OS</template>
                    <template v-slot:price>4599</template>
                </Goods>
                <Goods>
                    <template v-slot:img>
                        <img src="../../../img/Xiaomi 14.png" alt="">
                    </template>
                    <template v-slot:title>Xiaomi 14</template>
                    <template v-slot:desc>徕卡光学Summilux镜头小米澎湃OS第三代骁龙®8移动平台</template>
                    <template v-slot:price>3999</template>
                </Goods>
            </div>
        </div>
    </div>
</template>

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

<style>
.bgc {
    background-color: rgb(245, 245, 245);
    height: 614px;
    padding: 10px;
    user-select: none;
    min-width: 1900px
}

.main-box {
    width: 68%;
    margin: auto;
}

.left-img {
    float: left;
    cursor: pointer;
    margin-right: 7px;
}

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

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

App

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

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

<style></style>

v-for 循环

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
<template>
    <div class="goods">
        <div class="goods-img">
            <slot name="img"></slot>
        </div>
        <h3 class="title"><slot name="title"></slot></h3>
        <p class="desc"><slot name="desc"></slot></p>
        <p class="price"><slot name="price"></slot>元起</p>
    </div>
</template>


<style>
.goods {
    width: 240px;
    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 7px 14px 7px;
    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 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>

Part

 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
<template>
    <div class="bgc">
        <div class="main-box">
            <div class="left-img">
                <img src="../../../img/xiaomiphone.webp" alt="">
            </div>
            <div class="right-goods">
                <Goods v-for="(item, index) in dataList" :key="item.id">
                    <template v-slot:img>
                        <img :src="item.url" alt="">
                    </template>
                    <template v-slot:title>{{ item.title }}</template>
                    <template v-slot:desc>{{ item.desc }}</template>
                    <template v-slot:price>{{ item.price }}</template>
                </Goods>
            </div>
        </div>
    </div>
</template>

<script>
import Goods from './Goods.vue';
export default {
    data(){
        return{
            dataList: [
                {id: 1, url: '../../../img/Redmi Turbo 3.png', title: 'Redmi Turbo 3', desc: '性能旋风,席卷而来', price: 1999},
                {id: 2, url: '../../../img/Xiaomi Civi 4 Pro.png', title: 'Xiaomi Civi 4 Pro', desc: '徕卡光学Summilux镜头 | 5000万徕卡人像镜头', price: 2999},
                {id: 3, url: '../../../img/Xiaomi 14 Ultra.png', title: 'Xiaomi 14 Ultra', desc: '徕卡全明星四摄 | 双向卫星通信  | 小米澎湃OS', price: 6499},
                {id: 4, url: '../../../img/Redmi K70 Pro.jpg', title: 'Redmi K70 Pro', desc: '第三代骁龙8 年度旗舰平台', price: 3299},
                {id: 5, url: '../../../img/Redmi K70.png', title: 'Redmi K70', desc: '第二代骁龙8 旗舰芯', price: 2399},
                {id: 6, url: '../../../img/Redmi K70E.png', title: 'Redmi K70E', desc: '新一代旗舰焊门员', price: 1799},
                {id: 7, url: '../../../img/Xiaomi 14 Pro.png', title: 'Xiaomi 14 Pro', desc: '徕卡Summilux可变光圈镜头|小米澎湃OS', price: 4599},
                {id: 8, url: '../../../img/Xiaomi 14.png', title: 'img/Xiaomi 14', desc: '徕卡光学Summilux镜头|小米澎湃OS|第三代骁龙®8移动平台', price: 3999},
            ]
        }
    },
    components: {
        Goods
    }
}
</script>

<style>
.bgc {
    background-color: rgb(245, 245, 245);
    height: 614px;
    padding: 10px;
    user-select: none;
    min-width: 1900px
}

.main-box {
    width: 68%;
    margin: auto;
}

.left-img {
    float: left;
    cursor: pointer;
    margin-right: 7px;
}

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

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

App

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

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

<style></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
<template>
    <div class="goods">
        <div class="goods-img">
            <slot name="img"></slot>
        </div>
        <h3 class="title"><slot name="title"></slot></h3>
        <p class="desc"><slot name="desc"></slot></p>
        <p class="price"><slot name="price"></slot>元起</p>
    </div>
</template>


<style>
.goods {
    width: 240px;
    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 7px 14px 7px;
    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 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>

Part

 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
<template>
    <div class="bgc">
        <div class="main-box">
            <div class="left-img">
                <slot name="left"></slot>
            </div>
            <div class="right-goods">
                <slot name="right"></slot>
            </div>
        </div>
    </div>
</template>

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

<style>
.bgc {
    background-color: rgb(245, 245, 245);
    height: 614px;
    padding: 10px;
    user-select: none;
    min-width: 1900px
}

.main-box {
    width: 68%;
    margin: auto;
}

.left-img {
    float: left;
    cursor: pointer;
    margin-right: 7px;
}

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

.left-img img:hover {
    box-shadow: 0 0 15px #cccccc;
    transform: translate(0, -2px);
}
</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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<template>
  <Part>
    <template v-slot:left>
      <img src="../../../img/xiaomiphone.webp" alt="">
    </template>
    <template v-slot:right>
      <Goods v-for="(item, index) in dataList1" :key="item.id">
        <template v-slot:img>
          <img :src="item.url" alt="">
        </template>
        <template v-slot:title>{{ item.title }}</template>
        <template v-slot:desc>{{ item.desc }}</template>
        <template v-slot:price>{{ item.price }}</template>
      </Goods>
    </template>
  </Part>
</template>

<script>
import Part from './components/xiaomi/Part.vue';
import Goods from './components/xiaomi/Goods.vue';

export default {
  data() {
    return {
      dataList1: [
        { id: 1, url: '../../../img/Redmi Turbo 3.png', title: 'Redmi Turbo 3', desc: '性能旋风,席卷而来', price: 1999 },
        { id: 2, url: '../../../img/Xiaomi Civi 4 Pro.png', title: 'Xiaomi Civi 4 Pro', desc: '徕卡光学Summilux镜头 | 5000万徕卡人像镜头', price: 2999 },
        { id: 3, url: '../../../img/Xiaomi 14 Ultra.png', title: 'Xiaomi 14 Ultra', desc: '徕卡全明星四摄 | 双向卫星通信  | 小米澎湃OS', price: 6499 },
        { id: 4, url: '../../../img/Redmi K70 Pro.jpg', title: 'Redmi K70 Pro', desc: '第三代骁龙8 年度旗舰平台', price: 3299 },
        { id: 5, url: '../../../img/Redmi K70.png', title: 'Redmi K70', desc: '第二代骁龙8 旗舰芯', price: 2399 },
        { id: 6, url: '../../../img/Redmi K70E.png', title: 'Redmi K70E', desc: '新一代旗舰焊门员', price: 1799 },
        { id: 7, url: '../../../img/Xiaomi 14 Pro.png', title: 'Xiaomi 14 Pro', desc: '徕卡Summilux可变光圈镜头|小米澎湃OS', price: 4599 },
        { id: 8, url: '../../../img/Xiaomi 14.png', title: 'img/Xiaomi 14', desc: '徕卡光学Summilux镜头|小米澎湃OS|第三代骁龙®8移动平台', price: 3999 },
      ],
    }
  },
  components: {
    Part,
    Goods,
  }
}
</script>

<style></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
<template>
    <div class="goods">
        <div class="goods-img">
            <slot name="img"></slot>
        </div>
        <h3 class="title"><slot name="title"></slot></h3>
        <p class="desc"><slot name="desc"></slot></p>
        <p class="price"><slot name="price"></slot>元起</p>
    </div>
</template>


<style>
.goods {
    width: 240px;
    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 7px 14px 7px;
    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 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>

Extra

 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
<template>
    <div class="extra">
        <div class="etc">
            <!-- <img src="../../../img/小米手环8 NFC版.jpg" alt=""> -->
            <slot name="etc-img"></slot>
            <h3 class="title"><slot name="title"></slot></h3>
            <p class="price"><slot name="price"></slot>元起</p>
        </div>
        <div class="more">
            <div class="more-icon">
                <img src="../../../img/more.png" alt="">
            </div>
            <div class="more-text">
                <div>浏览更多</div>
                <div><slot name="type"></slot></div>
            </div>
        </div>
    </div>
</template>

<style>
.extra {
    width: 240px;
    height: 300px;
    box-sizing: border-box;
    font-family: "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei", "Hiragino Sans GB", "Heiti SC", "WenQuanYi Micro Hei", sans-serif;
    float: left;
    margin: 0 7px 14px 7px;
    user-select: none;
}

.etc,
.more {
    width: 240px;
    height: 143px;
    background-color: white;
    margin: 0 0 14px 0;
    transition: 0.5s;
    cursor: pointer;
}

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

.etc img {
    width: 80px;
    height: 80px;
    float: right;
    margin: 31.5px 30px 0 0;
}

.extra h3,
.extra p {
    font-weight: 100;
    font-size: 14px;
    margin: 0;
    padding-left: 30px;
}

.extra .price {
    color: rgb(255, 103, 0);
}

.extra h3 {
    padding: 45px 0 15px 30px;
}

.more .more-icon img{
    width: 52px;
    height: 52px;
    float: right;
    margin: 45.5px 45px 0 0;
}

.more .more-text div:nth-child(1){
    font-size: 18px;
    padding: 49px 0 5px 30px;
}

.more .more-text div:nth-child(2){
    font-size: 12px;
    padding: 0 0 0 30px;
    color: rgb(117, 117, 117);
}
</style>

<script>
</script>

Part

 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
<template>
    <div class="bgc">
        <div class="main-box">
            <div class="left-img">
                <slot name="left"></slot>
            </div>
            <div class="right-goods">
                <slot name="right"></slot>
            </div>
        </div>
    </div>
</template>

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

<style>
.bgc {
    background-color: rgb(245, 245, 245);
    height: 614px;
    padding: 10px;
    user-select: none;
    min-width: 1900px
}

.main-box {
    width: 68%;
    margin: auto;
}

.left-img {
    float: left;
    cursor: pointer;
    margin-right: 7px;
}

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

.left-img img:hover {
    box-shadow: 0 0 15px #cccccc;
    transform: translate(0, -2px);
}
</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
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
<template>
  <Part>
    <template v-slot:left>
      <img src="../../../img/xiaomiphone.webp" alt="">
    </template>
    <template v-slot:right>
      <Goods v-for="(item, index) in dataList1" :key="item.id">
        <template v-slot:img>
          <img :src="item.url" alt="">
        </template>
        <template v-slot:title>{{ item.title }}</template>
        <template v-slot:desc>{{ item.desc }}</template>
        <template v-slot:price>{{ item.price }}</template>
      </Goods>
    </template>
  </Part>
  <Part>
    <template v-slot:left>
      <img src="../../../img/xiaomiwatch.webp" alt="">
    </template>
    <template v-slot:right>
      <Goods v-for="(item, index) in dataList2" :key="item.id">
        <template v-slot:img>
          <img :src="item.url" alt="">
        </template>
        <template v-slot:title>{{ item.title }}</template>
        <template v-slot:desc>{{ item.desc }}</template>
        <template v-slot:price>{{ item.price }}</template>
      </Goods>
      <Extra v-show="dataList2.length < 8">
        <template v-slot:etc-img>
          <img src="../../../img/小米手环8 NFC版.jpg" alt="">
        </template>
        <template v-slot:title>小米手环8</template>
        <template v-slot:price>209</template>
        <template v-slot:type>穿戴</template>
      </Extra>
    </template>
  </Part>
</template>

<script>
import Part from './components/xiaomi/Part.vue';
import Goods from './components/xiaomi/Goods.vue';
import Extra from './components/xiaomi/Extra.vue';

export default {
  data() {
    return {
      dataList1: [
        { id: 1, url: '../../../img/Redmi Turbo 3.png', title: 'Redmi Turbo 3', desc: '性能旋风,席卷而来', price: 1999 },
        { id: 2, url: '../../../img/Xiaomi Civi 4 Pro.png', title: 'Xiaomi Civi 4 Pro', desc: '徕卡光学Summilux镜头 | 5000万徕卡人像镜头', price: 2999 },
        { id: 3, url: '../../../img/Xiaomi 14 Ultra.png', title: 'Xiaomi 14 Ultra', desc: '徕卡全明星四摄 | 双向卫星通信  | 小米澎湃OS', price: 6499 },
        { id: 4, url: '../../../img/Redmi K70 Pro.jpg', title: 'Redmi K70 Pro', desc: '第三代骁龙8 年度旗舰平台', price: 3299 },
        { id: 5, url: '../../../img/Redmi K70.png', title: 'Redmi K70', desc: '第二代骁龙8 旗舰芯', price: 2399 },
        { id: 6, url: '../../../img/Redmi K70E.png', title: 'Redmi K70E', desc: '新一代旗舰焊门员', price: 1799 },
        { id: 7, url: '../../../img/Xiaomi 14 Pro.png', title: 'Xiaomi 14 Pro', desc: '徕卡Summilux可变光圈镜头|小米澎湃OS', price: 4599 },
        { id: 8, url: '../../../img/Xiaomi 14.png', title: 'img/Xiaomi 14', desc: '徕卡光学Summilux镜头|小米澎湃OS|第三代骁龙®8移动平台', price: 3999 },
      ],
      dataList2: [
        { id: 1, url: '../../../img/小米手环8 Pro 原神定制版.jpg', title: '小米手环8 Pro 原神定制版', desc: '达达利亚主题定制手环 | 主题定制充电底座 | 专属定制礼盒', price: 549 },
        { id: 2, url: '../../../img/Redmi Watch 4.jpg', title: 'Redmi Watch 4', desc: '1.97英寸AMOLED大屏丨潮流金属表框丨20天超长续航', price: 499 },
        { id: 3, url: '../../../img/Xiaomi Watch S3.jpg', title: 'Xiaomi Watch S3', desc: '百变表圈 | 小米澎湃OS | 12通道心率检测模组', price: 799 },
        { id: 4, url: '../../../img/小米腕部心电血压记录仪.png', title: '小米腕部心电血压记录仪', desc: '血压测量|心电采集|跌倒检测 紧急呼救|蓝牙通话', price: 1999 },
        { id: 5, url: '../../../img/小米手环 8 Pro.jpg', title: '小米手环 8 Pro', desc: '1.74″AMOLED炫彩大屏 | 手表级健康监测 | 独立GNSS定位', price: 379 },
        { id: 6, url: '../../../img/Redmi Watch 3 青春版.png', title: 'Redmi Watch 3 青春版', desc: '1.83"超大屏幕|腕上蓝牙通话|全天候血氧监测', price: 329 },
        { id: 7, url: '../../../img/小米手环8 NFC版.jpg', title: '小米手环8 NFC版', desc: '多样快拆时尚腕带 | 跑步豆&体感互动多模式 | 多功能NFC', price: 249 },
        // { id: 8, url: '../../../img/米兔儿童学习手表5 Pro.jpg', title: 'img/米兔儿童学习手表5 Pro', desc: '12重安全定位 | 3D楼层定位 | 高清双摄 | AI拍照识物 | NFC公交卡 | 实时心率监测 | 20米防水 | 儿童微信 | QQ | 支付宝 | 小爱同学', price: 999 },
      ]
    }
  },
  components: {
    Part,
    Goods,
    Extra
  }
}
</script>

<style></style>

练习

  1. 可以通过()标签为组件添加插槽?

  2. 如果要把内容填充到指定名称的插槽中,可以通过一个包含()指令的 <template> 标签来实现。

  3. 如果一个组件没有预留任何插槽,则组件的使用者提供的任何插槽内容同样会起作用。()

  4. 添加 name 属性的 <slot> 标签用来定义具名插槽。()

  5. dom 元素在哪个生命周期后才能后被调用?

​ A. onActived() B. mounted() C. beforeCreate() D. beforeMount()

  1. 下列说法,关于自定义指令说法错误的是。()

​ A. 插槽是组件封装期间为组件的使用者预留的占位符。

​ B. 在定义插槽时,直接写一个 <slot> 标签,它属于默认插槽。

​ C. 如果组件的使用者为插槽提供内容,则默认内容生效。

​ D. 当需要使用多个插槽时,则需要为每个 <slot> 插槽指定具体的 name 属性。

  1. 下列选项中,关于自定义指令说法错误的是。()

​ A. 全局自定义指令可以在全局进行使用。

​ B. 私有自定义指令只能够在声明该指令的组件中使用。

​ C. 在 Vue 中,可以通过 app.directive() 函数声明全局自定义指令。

​ D. 在 Vue 中,不能为自定义指令绑定参数。

  1. 下列选项中,关于自定义指令常用声明周期函数及传入参数说法错误的是。()

​ A. mounted() 函数在绑定元素的父组件及自身的所有子节点都挂在完成后调用。

​ B. value 为参数 binding 中的属性,表示传递给指令的值。

​ C. beforeUpdate() 函数在绑定的父组件卸载前调用。

​ D. el 参数表示当前指令所绑定到的元素。

Blog for Sandy Memories