【B站 heima】小兔鲜Vue3 项目学习笔记Day04

news2024/11/23 10:15:46

文章目录

  • 二级分类
    • 1.整体认识和路由配置
    • 2.面包屑导航功能实现
    • 3. 基础商品列表实现
    • 4. 定制路由滚动行为
  • 详情页
    • 1.整体认识和路由配置
    • 2.基础数据渲染
    • 3.热榜区域实现
    • 4. 图片预览组件封装
    • 5.放大镜-滑块跟随移动
      • 左侧滑块跟随鼠标移动
      • 放大镜-大图效果
    • 6. props适配
    • 7. SKU组件熟悉使用
    • 8. 通用组件统一注册为全局组件
    • 小结

持续更新~~

二级分类

1.整体认识和路由配置

在这里插入图片描述
在这里插入图片描述

步骤:

  • 创建路由组件,静态模板
<!--views/subCategory/index.vue-->
<script setup>


</script>

<template>
    <div class="container ">
        <!-- 面包屑 -->
        <div class="bread-container">
            <el-breadcrumb separator=">">
                <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                <el-breadcrumb-item :to="{ path: '/' }">居家
                </el-breadcrumb-item>
                <el-breadcrumb-item>居家生活用品</el-breadcrumb-item>
            </el-breadcrumb>
        </div>
        <div class="sub-container">
            <el-tabs>
                <el-tab-pane label="最新商品" name="publishTime"></el-tab-pane>
                <el-tab-pane label="最高人气" name="orderNum"></el-tab-pane>
                <el-tab-pane label="评论最多" name="evaluateNum"></el-tab-pane>
            </el-tabs>
            <div class="body">
                <!-- 商品列表-->
            </div>
        </div>
    </div>

</template>



<style lang="scss" scoped>
.bread-container {
    padding: 25px 0;
    color: #666;
}

.sub-container {
    padding: 20px 10px;
    background-color: #fff;

    .body {
        display: flex;
        flex-wrap: wrap;
        padding: 0 10px;
    }

    .goods-item {
        display: block;
        width: 220px;
        margin-right: 20px;
        padding: 20px 30px;
        text-align: center;

        img {
            width: 160px;
            height: 160px;
        }

        p {
            padding-top: 10px;
        }

        .name {
            font-size: 16px;
        }

        .desc {
            color: #999;
            height: 29px;
        }

        .price {
            color: $priceColor;
            font-size: 20px;
        }
    }

    .pagination-container {
        margin-top: 20px;
        display: flex;
        justify-content: center;
    }


}
</style>
  • 配置路由关系

在这里插入图片描述

//router/index.js
import subCategory from '@/views/subCategory/index.vue'

//在route的children配置二级路由
 {
          path: 'category/sub/:id',
          component: subCategory
 }
  • 修改模板实现跳转
<!--Category/index.vue-->
 <!-- 分类列表 -->
            <div class="sub-list">
                <h3>全部分类</h3>
                <ul>
                    <li v-for="i in categoryData.children" :key="i.id">
                        <RouterLink :to="`/category/sub/${i.id}`">
                            <img :src="i.picture" />
                            <p>{{ i.name }}</p>
                        </RouterLink>
                    </li>
                </ul>
            </div>

最终效果:

在这里插入图片描述

2.面包屑导航功能实现

步骤:

  • 封装接口,获取面包屑数据
/**
	apis/category.js
 * @description: 获取二级分类列表数据
 * @param {*} id 分类id 
 * @return {*}
 */

export const getCategoryFilterAPI = (id) => {
    return request({
        url: '/category/sub/filter',
        params: {
            id
        }
    })
}
  • 调用接口渲染模板
<!-- subCategory/index.vue -->
<script setup>
import { getCategoryFilterAPI } from '@/apis/category.js'
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router';

const route = useRoute()
const categoryFilter = ref({})

//获取面包屑导航数据
const getCategoryFilter = async () => {
    const res = await getCategoryFilterAPI(route.params.id)
    categoryFilter.value = res.result
}
onMounted(() => {
    getCategoryFilter()
})
    </script>
<!-- 面包屑 -->
        <div class="bread-container">
            <el-breadcrumb separator=">">
                <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                <el-breadcrumb-item :to="{ path: `/category/${categoryFilter.parentId}` }">{{ categoryFilter.parentName
                    }}
                </el-breadcrumb-item>
                <el-breadcrumb-item>{{ categoryFilter.name }}</el-breadcrumb-item>
            </el-breadcrumb>
        </div>
  • 测试跳转

可以正常跳转,可以从面包屑这里进行跳转

在这里插入图片描述

3. 基础商品列表实现

在这里插入图片描述

实现流程:

  • 实现基础列表渲染(基础参数)

    • 封装接口
    /**             apis/category.js
     * @description: 获取导航数据
     * @data { 
            categoryId: 1005000 ,
            page: 1,
            pageSize: 20,
            sortField: 'publishTime' | 'orderNum' | 'evaluateNum'
        } 
     * @return {*}
     */
    export const getSubCategoryAPI = (data) => {
        return request({
            url: '/category/goods/temporary',
            method: 'POST',
            data
        })
    }
    
    • 准备基础参数
    //获取基础列表数据   views/subCategory/index.vue
    const baseListData = ref({
        category: route.params.id,
        page: 1,
        pageSize: 20,
        sortField: 'publishTime'
    })
    const getSubCategory = async () => {
        const res = await getSubCategoryAPI(baseListData.value)  //数据要传进去
        // console.log(res)
        baseListData.value = res.result.items
    }
    
    onMounted(() => getSubCategory())
    
    • 获取数据渲染列表,使用我们之前封装的GoodItem组件
    <script>import GoodItem from '../Home/components/GoodItem.vue'; </script>
    <div class="body">
                    <!-- 商品列表-->
                    <GoodItem :goods="goods" v-for="goods in baseListData" :key="goods.id" />
                </div>
    
  • 添加额外参数实现筛选功能

    • 获取激活项数据。使用新参数发送请求重新渲染列表

      使用的是elementPlusTabs标签,这个v-model绑定的是选项中name的值
      在这里插入图片描述

      使用这个方法,当选项改变时执行回调

      在这里插入图片描述

       <!-- tab切换 subCategory.vue-->
                  <el-tabs v-model="baseListData.sortField" @tab-change="tabChange">
                      <el-tab-pane label="最新商品" name="publishTime"></el-tab-pane>
                      <el-tab-pane label="最高人气" name="orderNum"></el-tab-pane>
                      <el-tab-pane label="评论最多" name="evaluateNum"></el-tab-pane>
                  </el-tabs>
      
      //切换tab执行的回调    subCategory.vue
      const tabChange = () => {
          baseListData.value.sortField = 1  //重置页数
          getSubCategory()  //重新请求数据
      }
      
  • 无限加载功能实现

在这里插入图片描述

使用elementPlus提供的v-infinite-scroll指令监听是否满足触底条件,满足加载条件时让页数参数加一获取下一页数据,做新老数据拼接渲染

步骤:

  • 配置v-infinite-scroll

在这里插入图片描述

相关代码  subCategory/index.vue
<div class="body" v-infinite-scroll="load">
    
    
//load回调
 const load = ()=>{
    console.log('加载更多数据喽')
}
  • 页数+1,获取下一页数据
	//页数加一
    baseListData.value.page++
    //获取下一页的数据
    const res = await getSubCategoryAPI(baseListData.value)    
  • 新老数据拼接
//将新旧数据拼接  使用...,把拼接的数组重新赋值给baseListData
    baseListData.value = [...baseListData.value, ...res.value.items]
  • 加载完毕结束监听
const disabled = ref(false)
//如果items为空,则停止加载
    if (baseListData.items.length === 0) {
        disabled.value = true
    }

  <div class="body" v-infinite-scroll="load" :infinite-scroll-disabled="disabled">

subCategory/index.vue 完整代码:

<!-- subCategory/index.vue -->
<script setup>
import { getCategoryFilterAPI, getSubCategoryAPI } from '@/apis/category.js'
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router';
import GoodItem from '../Home/components/GoodItem.vue';

const route = useRoute()

//获取面包屑导航数据
const categoryFilter = ref({})
const getCategoryFilter = async () => {
    const res = await getCategoryFilterAPI(route.params.id)
    categoryFilter.value = res.result
}
onMounted(() => {
    getCategoryFilter()
})

//获取基础列表数据
const baseListData = ref({
    category: route.params.id,
    page: 1,
    pageSize: 20,
    sortField: 'publishTime'
})
const getSubCategory = async () => {
    const res = await getSubCategoryAPI(baseListData.value)  //数据要传进去
    // console.log(res)
    baseListData.value = res.result.items
}

onMounted(() => getSubCategory())

//切换tab执行的回调
const tabChange = () => {
    baseListData.value.page = 1  //重置页数
    // console.log(baseListData.value.sortField)
    getSubCategory()  //重新请求数据
}

//无限滚动
const disabled = ref(false)
const load = async () => {
    // console.log('加载更多数据喽')
    //页数加一
    baseListData.value.page++
    //获取下一页的数据
    const res = await getSubCategoryAPI(baseListData.value)
    //将新旧数据拼接  使用...,把拼接的数组重新赋值给baseListData
    baseListData.value = [...baseListData.value, ...res.value.items]
    //如果items为空,则停止加载
    if (baseListData.items.length === 0) {
        disabled.value = true
    }
}
</script>

<template>
    <div class="container ">
        <!-- 面包屑 -->
        <div class="bread-container">
            <el-breadcrumb separator=">">
                <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                <el-breadcrumb-item :to="{ path: `/category/${categoryFilter.parentId}` }">{{ categoryFilter.parentName
                    }}
                </el-breadcrumb-item>
                <el-breadcrumb-item>{{ categoryFilter.name }}</el-breadcrumb-item>
            </el-breadcrumb>
        </div>
        <div class="sub-container">
            <!-- tab切换 -->
            <el-tabs v-model="baseListData.sortField" @tab-change="tabChange">
                <el-tab-pane label="最新商品" name="publishTime"></el-tab-pane>
                <el-tab-pane label="最高人气" name="orderNum"></el-tab-pane>
                <el-tab-pane label="评论最多" name="evaluateNum"></el-tab-pane>
            </el-tabs>
            <div class="body" v-infinite-scroll="load" :infinite-scroll-disabled="disabled">
                <!-- 商品列表-->
                <GoodItem :goods="goods" v-for="goods in baseListData" :key="goods.id" />
            </div>
        </div>
    </div>

</template>



<style lang="scss" scoped>
.bread-container {
    padding: 25px 0;
    color: #666;
}

.sub-container {
    padding: 20px 10px;
    background-color: #fff;

    .body {
        display: flex;
        flex-wrap: wrap;
        padding: 0 10px;
    }

    .goods-item {
        display: block;
        width: 220px;
        margin-right: 20px;
        padding: 20px 30px;
        text-align: center;

        img {
            width: 160px;
            height: 160px;
        }

        p {
            padding-top: 10px;
        }

        .name {
            font-size: 16px;
        }

        .desc {
            color: #999;
            height: 29px;
        }

        .price {
            color: $priceColor;
            font-size: 20px;
        }
    }

    .pagination-container {
        margin-top: 20px;
        display: flex;
        justify-content: center;
    }


}
</style>

4. 定制路由滚动行为

切换路由,自动滚动到页面的顶部

如何配置vue-router支持scrollBehavior配置项,可以指定路由切换的滚动位置。

//router/index.js

 //路由滚动行为定制
  scrollBehavior() {
    return {
      top: 0
    }
  }

详情页

1.整体认识和路由配置

路由:

  • 创建详情组件 Views/Detail/index.vue
<script setup>


</script>

<template>
  <div class="xtx-goods-page">
    <div class="container">
      <div class="bread-container">
        <el-breadcrumb separator=">">
          <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
          <el-breadcrumb-item :to="{ path: '/' }">母婴
          </el-breadcrumb-item>
          <el-breadcrumb-item :to="{ path: '/' }">跑步鞋
          </el-breadcrumb-item>
          <el-breadcrumb-item>抓绒保暖,毛毛虫子儿童运动鞋</el-breadcrumb-item>
        </el-breadcrumb>
      </div>
      <!-- 商品信息 -->
      <div class="info-container">
        <div>
          <div class="goods-info">
            <div class="media">
              <!-- 图片预览区 -->

              <!-- 统计数量 -->
              <ul class="goods-sales">
                <li>
                  <p>销量人气</p>
                  <p> 100+ </p>
                  <p><i class="iconfont icon-task-filling"></i>销量人气</p>
                </li>
                <li>
                  <p>商品评价</p>
                  <p>200+</p>
                  <p><i class="iconfont icon-comment-filling"></i>查看评价</p>
                </li>
                <li>
                  <p>收藏人气</p>
                  <p>300+</p>
                  <p><i class="iconfont icon-favorite-filling"></i>收藏商品</p>
                </li>
                <li>
                  <p>品牌信息</p>
                  <p>400+</p>
                  <p><i class="iconfont icon-dynamic-filling"></i>品牌主页</p>
                </li>
              </ul>
            </div>
            <div class="spec">
              <!-- 商品信息区 -->
              <p class="g-name"> 抓绒保暖,毛毛虫儿童鞋 </p>
              <p class="g-desc">好穿 </p>
              <p class="g-price">
                <span>200</span>
                <span> 100</span>
              </p>
              <div class="g-service">
                <dl>
                  <dt>促销</dt>
                  <dd>12月好物放送,App领券购买直降120元</dd>
                </dl>
                <dl>
                  <dt>服务</dt>
                  <dd>
                    <span>无忧退货</span>
                    <span>快速退款</span>
                    <span>免费包邮</span>
                    <a href="javascript:;">了解详情</a>
                  </dd>
                </dl>
              </div>
              <!-- sku组件 -->

              <!-- 数据组件 -->

              <!-- 按钮组件 -->
              <div>
                <el-button size="large" class="btn">
                  加入购物车
                </el-button>
              </div>

            </div>
          </div>
          <div class="goods-footer">
            <div class="goods-article">
              <!-- 商品详情 -->
              <div class="goods-tabs">
                <nav>
                  <a>商品详情</a>
                </nav>
                <div class="goods-detail">
                  <!-- 属性 -->
                  <ul class="attrs">
                    <li v-for="item in 3" :key="item.value">
                      <span class="dt">白色</span>
                      <span class="dd">纯棉</span>
                    </li>
                  </ul>
                  <!-- 图片 -->

                </div>
              </div>
            </div>
            <!-- 24热榜+专题推荐 -->
            <div class="goods-aside">

            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>


<style scoped lang='scss'>
.xtx-goods-page {
  .goods-info {
    min-height: 600px;
    background: #fff;
    display: flex;

    .media {
      width: 580px;
      height: 600px;
      padding: 30px 50px;
    }

    .spec {
      flex: 1;
      padding: 30px 30px 30px 0;
    }
  }

  .goods-footer {
    display: flex;
    margin-top: 20px;

    .goods-article {
      width: 940px;
      margin-right: 20px;
    }

    .goods-aside {
      width: 280px;
      min-height: 1000px;
    }
  }

  .goods-tabs {
    min-height: 600px;
    background: #fff;
  }

  .goods-warn {
    min-height: 600px;
    background: #fff;
    margin-top: 20px;
  }

  .number-box {
    display: flex;
    align-items: center;

    .label {
      width: 60px;
      color: #999;
      padding-left: 10px;
    }
  }

  .g-name {
    font-size: 22px;
  }

  .g-desc {
    color: #999;
    margin-top: 10px;
  }

  .g-price {
    margin-top: 10px;

    span {
      &::before {
        content: "¥";
        font-size: 14px;
      }

      &:first-child {
        color: $priceColor;
        margin-right: 10px;
        font-size: 22px;
      }

      &:last-child {
        color: #999;
        text-decoration: line-through;
        font-size: 16px;
      }
    }
  }

  .g-service {
    background: #f5f5f5;
    width: 500px;
    padding: 20px 10px 0 10px;
    margin-top: 10px;

    dl {
      padding-bottom: 20px;
      display: flex;
      align-items: center;

      dt {
        width: 50px;
        color: #999;
      }

      dd {
        color: #666;

        &:last-child {
          span {
            margin-right: 10px;

            &::before {
              content: "•";
              color: $xtxColor;
              margin-right: 2px;
            }
          }

          a {
            color: $xtxColor;
          }
        }
      }
    }
  }

  .goods-sales {
    display: flex;
    width: 400px;
    align-items: center;
    text-align: center;
    height: 140px;

    li {
      flex: 1;
      position: relative;

      ~li::after {
        position: absolute;
        top: 10px;
        left: 0;
        height: 60px;
        border-left: 1px solid #e4e4e4;
        content: "";
      }

      p {
        &:first-child {
          color: #999;
        }

        &:nth-child(2) {
          color: $priceColor;
          margin-top: 10px;
        }

        &:last-child {
          color: #666;
          margin-top: 10px;

          i {
            color: $xtxColor;
            font-size: 14px;
            margin-right: 2px;
          }

          &:hover {
            color: $xtxColor;
            cursor: pointer;
          }
        }
      }
    }
  }
}

.goods-tabs {
  min-height: 600px;
  background: #fff;

  nav {
    height: 70px;
    line-height: 70px;
    display: flex;
    border-bottom: 1px solid #f5f5f5;

    a {
      padding: 0 40px;
      font-size: 18px;
      position: relative;

      >span {
        color: $priceColor;
        font-size: 16px;
        margin-left: 10px;
      }
    }
  }
}

.goods-detail {
  padding: 40px;

  .attrs {
    display: flex;
    flex-wrap: wrap;
    margin-bottom: 30px;

    li {
      display: flex;
      margin-bottom: 10px;
      width: 50%;

      .dt {
        width: 100px;
        color: #999;
      }

      .dd {
        flex: 1;
        color: #666;
      }
    }
  }

  >img {
    width: 100%;
  }
}

.btn {
  margin-top: 20px;

}

.bread-container {
  padding: 25px 0;
}
</style>
  • 绑定路由关系(参数),绑定模板
//router/index.js
import Detail from '@/views/Detail/index.vue'

//二级路由
{
          path: 'detail/:id',
          component: Detail
        }

<!--HomeNew.vue--> 
<RouterLink :to="`/detail/${item.id}`">
                        <img :src="item.picture" alt="" />
                        <p class="name">{{ item.name }}</p>
                        <p class="price">&yen;{{ item.price }}</p>
                    </RouterLink>

效果:

在这里插入图片描述

2.基础数据渲染

完成下图渲染,使用的统一接口

在这里插入图片描述

步骤:

  • 封装接口
//apis/detail.js
//获取详情数据
export function getDetailAPI(id) {
    return httpInstance({
        url: '/goods',
        params: {
            id
        }
    })
}
  • 获取数据
<!--Detail/index.vue-->
<script setup>
import { ref, onMounted } from 'vue';
import { getDetailAPI } from '@/apis/detail';
import { useRoute } from 'vue-router';

const goods = ref({})
const route = useRoute()
const getGoods = async () => {
    const res = await getDetailAPI(route.params.id)
    goods.value = res.result
}
onMounted(() => getGoods())
</script>

在这里插入图片描述

  • 渲染模板

面包屑导航

<!-- goods一开始时空对象,一开始访问是undefined[0] Detail/index.vue-->
                    <!-- 解决办法:1.可选链 2.v-if手动控制渲染时机,保证只有数据存在才渲染 -->
                    <el-breadcrumb-item :to="{ path: `/category/${goods.categories?.[1].id}` }">{{
                        goods.categories?.[1].name }}</el-breadcrumb-item>
                    <el-breadcrumb-item :to="{ path: `/category/${goods.categories?.[0].id}` }">{{
                        goods.categories?.[0].name }}
                    </el-breadcrumb-item>
<!-- 统计数量 Detail/index.vue-->
                            <ul class="goods-sales">
                                <li>
                                    <p>销量人气</p>
                                    <p> {{ goods.salesCount }}+ </p>
                                    <p><i class="iconfont icon-task-filling"></i>销量人气</p>
                                </li>
                                <li>
                                    <p>商品评价</p>
                                    <p>{{ goods.commitCount }}+</p>
                                    <p><i class="iconfont icon-comment-filling"></i>查看评价</p>
                                </li>
                                <li>
                                    <p>收藏人气</p>
                                    <p>{{ goods.collectCount }}+</p>
                                    <p><i class="iconfont icon-favorite-filling"></i>收藏商品</p>
                                </li>
                                <li>
                                    <p>品牌信息</p>
                                    <p>{{
                        goods.brand.name }}+</p>
                                    <p><i class="iconfont icon-dynamic-filling"></i>品牌主页</p>
                                </li>
                            </ul>

在这里插入图片描述

 <!-- 商品信息区 Detail/index.vue-->
                            <p class="g-name"> {{ goods.name }} </p>
                            <p class="g-desc">{{ goods.desc }}</p>
                            <p class="g-price">
                                <span>{{ goods.oldPrice }}</span>
                                <span> {{ goods.price }}</span>
                            </p>

在这里插入图片描述

<!-- 商品详情  Detail/index.vue-->
                            <div class="goods-tabs">
                                <nav>
                                    <a>商品详情</a>
                                </nav>
                                <div class="goods-detail">
                                    <!-- 属性 -->
                                    <ul class="attrs">
                                        <li v-for="item in goods.details?.properties" :key="item.value">
                                            <span class="dt">{{ item.name }}</span>
                                            <span class="dd">{{ item.value }}</span>
                                        </li>
                                    </ul>
                                    <!-- 图片 -->
                                    <img v-for="img in goods.details?.pictures" :src="img" :key="img" alt="" />
                                </div>
                            </div>
                        </div>

在这里插入图片描述

3.热榜区域实现

在这里插入图片描述

步骤:

  • 封装组件(因为结构一致)
<!-- DetailHot.vue -->
<script setup>

</script>


<template>
    <div class="goods-hot">
        <h3>周日榜单</h3>
        <!-- 商品区块 -->
        <RouterLink to="/" class="goods-item" v-for="item in 3" :key="item.id">
            <img :src="item.picture" alt="" />
            <p class="name ellipsis">一双男鞋</p>
            <p class="desc ellipsis">一双好穿的男鞋</p>
            <p class="price">&yen;200.00</p>
        </RouterLink>
    </div>
</template>


<style scoped lang="scss">
.goods-hot {
    h3 {
        height: 70px;
        background: $helpColor;
        color: #fff;
        font-size: 18px;
        line-height: 70px;
        padding-left: 25px;
        margin-bottom: 10px;
        font-weight: normal;
    }

    .goods-item {
        display: block;
        padding: 20px 30px;
        text-align: center;
        background: #fff;

        img {
            width: 160px;
            height: 160px;
        }

        p {
            padding-top: 10px;
        }

        .name {
            font-size: 16px;
        }

        .desc {
            color: #999;
            height: 29px;
        }

        .price {
            color: $priceColor;
            font-size: 20px;
        }
    }
}
</style>

在父组件中使用两次这个组件

 <!-- 24热榜+专题推荐 Detail/index.vue-->
import DetailHot from './components/DetailHot.vue'


<div class="goods-aside">
          <!-- 24小时 -->
          <DetailHot />
          <!-- 周日 -->
          <DetailHot />
</div>
  • 获取渲染基础数据
/**
 * 获取热榜商品
 * @param {Number} id - 商品id
 * @param {Number} type - 1代表24小时热销榜 2代表周热销榜
 * @param {Number} limit - 获取个数
 */
export const getHotGoodsAPI = ({ id, type, limit = 3 }) => {
    return httpInstance({
        url: '/goods/hot',
        params: {
            id,
            type,
            limit
        }
    })
}


<!--Detail/components/DetailHot.vue-->
<script setup>
import { ref } from 'vue'
import { getHotGoodsAPI } from '@/apis/detail'
import { useRoute } from 'vue-router'

const goodList = ref([])
const route = useRoute()
const getHotList = async () => {
  const res = await getHotGoodsAPI({
    id: route.params.id,
    type: 1
  })
  goodList.value = res.result
}
getHotList()


</script>
<template>
    <div class="goods-hot">
        <h3>周日榜单</h3>
        <!-- 商品区块 -->
        <RouterLink to="/" class="goods-item" v-for="item in goodList" :key="item.id">
            <img :src="item.picture" alt="" />
            <p class="name ellipsis">{{ item.name }}</p>
            <p class="desc ellipsis">{{ item.desc }}</p>
            <p class="price">&yen;{{ item.price }}</p>
        </RouterLink>
    </div>
</template>

在这里插入图片描述

  • 适配不同标题Title和内容

定义props,给两个组件绑定不同的数据

//热榜类型 1为24小时热榜 2为周热榜  DetailHot.vue
const props = defineProps({
    hotType: {
        type: Number
    }
})
const TYPEMAP = {
    1: '24小时热榜',
    2: '周热榜'
}
const title = computed(() => TYPEMAP[props.hotType])


  <h3>{{ title }}</h3>

type决定着获取哪种数据,我们将1替换成props.hotType即可。

const getHotList = async () => {
    const res = await getHotGoodsAPI({
        id: route.params.id,
        type: props.hotType
    })
    goodList.value = res.result

4. 图片预览组件封装

在这里插入图片描述

功能:

  • 小图切换大图功能

思路:维护一个数组图片列表,鼠标划入小图记录当前小图下标值,通过下标值在数组中取对应图片,显示到大图位置

步骤:

​ 准备组件静态模板(包括图片数据列表)

<!--component/ImageView/index.vue-->
<script setup>
// 图片列表
const imageList = [
  "https://yanxuan-item.nosdn.127.net/d917c92e663c5ed0bb577c7ded73e4ec.png",
  "https://yanxuan-item.nosdn.127.net/e801b9572f0b0c02a52952b01adab967.jpg",
  "https://yanxuan-item.nosdn.127.net/b52c447ad472d51adbdde1a83f550ac2.jpg",
  "https://yanxuan-item.nosdn.127.net/f93243224dc37674dfca5874fe089c60.jpg",
  "https://yanxuan-item.nosdn.127.net/f881cfe7de9a576aaeea6ee0d1d24823.jpg"
]
</script>


<template>
  <div class="goods-image">
    <!-- 左侧大图-->
    <div class="middle" ref="target">
      <img :src="imageList[0]" alt="" />
      <!-- 蒙层小滑块 -->
      <div class="layer" :style="{ left: `0px`, top: `0px` }"></div>
    </div>
    <!-- 小图列表 -->
    <ul class="small">
      <li v-for="(img, i) in imageList" :key="i">
        <img :src="img" alt="" />
      </li>
    </ul>
    <!-- 放大镜大图 -->
    <div class="large" :style="[
      {
        backgroundImage: `url(${imageList[0]})`,
        backgroundPositionX: `0px`,
        backgroundPositionY: `0px`,
      },
    ]" v-show="false"></div>
  </div>
</template>

<style scoped lang="scss">
.goods-image {
  width: 480px;
  height: 400px;
  position: relative;
  display: flex;

  .middle {
    width: 400px;
    height: 400px;
    background: #f5f5f5;
  }

  .large {
    position: absolute;
    top: 0;
    left: 412px;
    width: 400px;
    height: 400px;
    z-index: 500;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    background-repeat: no-repeat;
    // 背景图:盒子的大小 = 2:1  将来控制背景图的移动来实现放大的效果查看 background-position
    background-size: 800px 800px;
    background-color: #f8f8f8;
  }

  .layer {
    width: 200px;
    height: 200px;
    background: rgba(0, 0, 0, 0.2);
    // 绝对定位 然后跟随咱们鼠标控制left和top属性就可以让滑块移动起来
    left: 0;
    top: 0;
    position: absolute;
  }

  .small {
    width: 80px;

    li {
      width: 68px;
      height: 68px;
      margin-left: 12px;
      margin-bottom: 15px;
      cursor: pointer;

      &:hover,
      &.active {
        border: 2px solid $xtxColor;
      }
    }
  }
}
</style>

引入,并使用组件

<!-- 图片预览区 Detail/index.vue-->
<ImageView />

为小图绑定事件mouseEnter,记录当前激活下标值activeIndex,通过下标i切换大图显示,通过下标实现激活状态显示

//ImageView/index.vue
const activeIndex = ref(null)
//鼠标移入小图回调
const mouseEnter = (i) => {
    activeIndex.value = i
}


 <!-- 小图列表 -->
        <ul class="small">
            <li v-for="(img, i) in imageList" :key="i" @mouseenter="mouseEnter(i)">
                <img :src="img" alt="" />
            </li>
        </ul>

在这里插入图片描述

鼠标离开也激活

 <li v-for="(img, i) in   imageList  " :key="i" @mouseenter="mouseEnter(i)"
                :class="{ active: i === activeIndex }">
                
                
 //激活样式scss
 &.active {
                border: 2px solid $xtxColor;
            }

5.放大镜-滑块跟随移动

核心功能:左侧滑块跟随鼠标移动、右侧大图放大效果实现、滑块和大图的显示与隐藏

左侧滑块跟随鼠标移动

使用useMouseInElement

在这里插入图片描述

<script setup>
import { ref } from 'vue';
import { useMouseInElement } from '@vueuse/core';
import { watch } from 'vue';
// 图片列表
const imageList = [
    "https://yanxuan-item.nosdn.127.net/d917c92e663c5ed0bb577c7ded73e4ec.png",
    "https://yanxuan-item.nosdn.127.net/e801b9572f0b0c02a52952b01adab967.jpg",
    "https://yanxuan-item.nosdn.127.net/b52c447ad472d51adbdde1a83f550ac2.jpg",
    "https://yanxuan-item.nosdn.127.net/f93243224dc37674dfca5874fe089c60.jpg",
    "https://yanxuan-item.nosdn.127.net/f881cfe7de9a576aaeea6ee0d1d24823.jpg"
]
const activeIndex = ref(null)
//鼠标移入小图回调
const mouseEnter = (i) => {
    activeIndex.value = i
}

//2.获取鼠标相对位置
const target = ref(null)
const { elementX, elementY, isOutside } = useMouseInElement(target)

//3.控制滑块跟随鼠标移动,监听elementX/Y变化,一旦变化,重新设置left/top
const left = ref(0)
const top = ref(0)
watch([elementX, elementY], () => {
    //有效范围控制滑块距离
    //横向
    if (elementX.value > 100 && elementX.value < 300) {
        left.value = elementX.value - 100
    }
    //纵向
    if (elementY.value > 100 && elementY.value < 300) {
        top.value = elementY.value - 100
    }

    //处理边界
    if (elementX.value > 300) { left.value = 200 }
    if (elementX.value < 100) { left.value = 0 }

    if (elementY.value > 300) { top.value = 200 }
    if (elementY.value < 100) { top.value = 0 }
})
</script>


<template>
    <div class="goods-image">
        <!-- 左侧大图-->
        <div class="middle" ref="target">
            <img :src="imageList[activeIndex]" alt="" />
            <!-- 蒙层小滑块 -->
            <div class="layer" :style="{ left: `${left}px`, top: `${top}px` }"></div>
        </div>
        <!-- 小图列表 -->
        <ul class="small">
            <li v-for="(img, i) in   imageList  " :key="i" @mouseenter="mouseEnter(i)"
                :class="{ active: i === activeIndex }">
                <img :src="img" alt="" />
            </li>
        </ul>
        <!-- 放大镜大图 -->
        <div class="large" :style="[
                {
                    backgroundImage: `url(${imageList[0]})`,
                    backgroundPositionX: `0px`,
                    backgroundPositionY: `0px`,
                },
            ]
                " v-show="false"></div>
    </div>
</template>

<style scoped lang="scss">
.goods-image {
    width: 480px;
    height: 400px;
    position: relative;
    display: flex;

    .middle {
        width: 400px;
        height: 400px;
        background: #f5f5f5;
    }

    .large {
        position: absolute;
        top: 0;
        left: 412px;
        width: 400px;
        height: 400px;
        z-index: 500;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        background-repeat: no-repeat;
        // 背景图:盒子的大小 = 2:1  将来控制背景图的移动来实现放大的效果查看 background-position
        background-size: 800px 800px;
        background-color: #f8f8f8;
    }

    .layer {
        width: 200px;
        height: 200px;
        background: rgba(0, 0, 0, 0.2);
        // 绝对定位 然后跟随咱们鼠标控制left和top属性就可以让滑块移动起来
        left: 0;
        top: 0;
        position: absolute;
    }

    .small {
        width: 80px;

        li {
            width: 68px;
            height: 68px;
            margin-left: 12px;
            margin-bottom: 15px;
            cursor: pointer;

            &:hover,
            &.active {
                border: 2px solid $xtxColor;
            }
        }
    }
}
</style>

放大镜-大图效果

大图的宽高是小图的两倍

实现思路:大图的移动方向和滑动移动方向相反,且数值两倍

<script setup>
import { ref } from 'vue';
import { useMouseInElement } from '@vueuse/core';
import { watch } from 'vue';
// 图片列表
const imageList = [
    "https://yanxuan-item.nosdn.127.net/d917c92e663c5ed0bb577c7ded73e4ec.png",
    "https://yanxuan-item.nosdn.127.net/e801b9572f0b0c02a52952b01adab967.jpg",
    "https://yanxuan-item.nosdn.127.net/b52c447ad472d51adbdde1a83f550ac2.jpg",
    "https://yanxuan-item.nosdn.127.net/f93243224dc37674dfca5874fe089c60.jpg",
    "https://yanxuan-item.nosdn.127.net/f881cfe7de9a576aaeea6ee0d1d24823.jpg"
]
const activeIndex = ref(null)
//鼠标移入小图回调
const mouseEnter = (i) => {
    activeIndex.value = i
}

//2.获取鼠标相对位置
const target = ref(null)
const { elementX, elementY, isOutside } = useMouseInElement(target)

//3.控制滑块跟随鼠标移动,监听elementX/Y变化,一旦变化,重新设置left/top
const left = ref(0)
const top = ref(0)
const positionX = ref(0)
const positionY = ref(0)
watch([elementX, elementY], () => {
    //如果鼠标未移入盒子,下列逻辑不执行
    if (isOutside.value) return

    //有效范围控制滑块距离
    //横向
    if (elementX.value > 100 && elementX.value < 300) {
        left.value = elementX.value - 100
    }
    //纵向
    if (elementY.value > 100 && elementY.value < 300) {
        top.value = elementY.value - 100
    }

    //处理边界
    if (elementX.value > 300) { left.value = 200 }
    if (elementX.value < 100) { left.value = 0 }

    if (elementY.value > 300) { top.value = 200 }
    if (elementY.value < 100) { top.value = 0 }

    //控制大图的显示
    positionX.value = -left.value * 2
    positionY.value = -top.value * 2
})
</script>


<template>
    <div class="goods-image">
        <!-- 左侧大图-->
        <div class="middle" ref="target">
            <img :src="imageList[activeIndex]" alt="" />
            <!-- 蒙层小滑块 -->
            <div class="layer" v-show="!isOutside" :style="{ left: `${left}px`, top: `${top}px` }"></div>
        </div>
        <!-- 小图列表 -->
        <ul class="small">
            <li v-for="(img, i) in   imageList  " :key="i" @mouseenter="mouseEnter(i)"
                :class="{ active: i === activeIndex }">
                <img :src="img" alt="" />
            </li>
        </ul>
        <!-- 放大镜大图 -->
        <div class="large" :style="[
                {
                    backgroundImage: `url(${imageList[0]})`,
                    backgroundPositionX: `${positionX}px`,
                    backgroundPositionY: `${positionY}px`,
                },
            ]
                " v-show="!isOutside"></div>
    </div>
</template>

<style scoped lang="scss">
.goods-image {
    width: 480px;
    height: 400px;
    position: relative;
    display: flex;

    .middle {
        width: 400px;
        height: 400px;
        background: #f5f5f5;
    }

    .large {
        position: absolute;
        top: 0;
        left: 412px;
        width: 400px;
        height: 400px;
        z-index: 500;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        background-repeat: no-repeat;
        // 背景图:盒子的大小 = 2:1  将来控制背景图的移动来实现放大的效果查看 background-position
        background-size: 800px 800px;
        background-color: #f8f8f8;
    }

    .layer {
        width: 200px;
        height: 200px;
        background: rgba(0, 0, 0, 0.2);
        // 绝对定位 然后跟随咱们鼠标控制left和top属性就可以让滑块移动起来
        left: 0;
        top: 0;
        position: absolute;
    }

    .small {
        width: 80px;

        li {
            width: 68px;
            height: 68px;
            margin-left: 12px;
            margin-bottom: 15px;
            cursor: pointer;

            &:hover,
            &.active {
                border: 2px solid $xtxColor;
            }
        }
    }
}
</style>

在这里插入图片描述

6. props适配

//ImageView.vue
defineProps({
    imageList: {
        type: Array,
        default: () => { }
    }
})
 <!-- 图片预览区   Detail/index.vue-->
<ImageView :image-list="goods.mainPictures"/>

7. SKU组件熟悉使用

在实际工作中,经常遇到别人写好的组件。熟悉一个三方组件,重点看什么?

答:props和emit。验证必要数据是否交互功能正常,点击选择规格是否正常产出数据。

三方 文件准备好了,就是资料里的XtxSku(一个index.vue,一个power-set.js文件)文件夹,粘到components文件夹下即可

<!-- XtsSku/index.vue -->
<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.id">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="val in item.values" :key="val.name">
          <img :class="{ selected: val.selected, disabled: val.disabled }" @click="clickSpecs(item, val)"
            v-if="val.picture" :src="val.picture" />
          <span :class="{ selected: val.selected, disabled: val.disabled }" @click="clickSpecs(item, val)" v-else>{{
      val.name
    }}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>
<script>
import { watchEffect } from 'vue'
import getPowerSet from './power-set'
const spliter = '★'
// 根据skus数据得到路径字典对象
const getPathMap = (skus) => {
  const pathMap = {}
  if (skus && skus.length > 0) {
    skus.forEach(sku => {
      // 1. 过滤出有库存有效的sku
      if (sku.inventory) {
        // 2. 得到sku属性值数组
        const specs = sku.specs.map(spec => spec.valueName)
        // 3. 得到sku属性值数组的子集
        const powerSet = getPowerSet(specs)
        // 4. 设置给路径字典对象
        powerSet.forEach(set => {
          const key = set.join(spliter)
          // 如果没有就先初始化一个空数组
          if (!pathMap[key]) {
            pathMap[key] = []
          }
          pathMap[key].push(sku.id)
        })
      }
    })
  }
  return pathMap
}

// 初始化禁用状态
function initDisabledStatus(specs, pathMap) {
  if (specs && specs.length > 0) {
    specs.forEach(spec => {
      spec.values.forEach(val => {
        // 设置禁用状态
        val.disabled = !pathMap[val.name]
      })
    })
  }
}

// 得到当前选中规格集合
const getSelectedArr = (specs) => {
  const selectedArr = []
  specs.forEach((spec, index) => {
    const selectedVal = spec.values.find(val => val.selected)
    if (selectedVal) {
      selectedArr[index] = selectedVal.name
    } else {
      selectedArr[index] = undefined
    }
  })
  return selectedArr
}

// 更新按钮的禁用状态
const updateDisabledStatus = (specs, pathMap) => {
  // 遍历每一种规格
  specs.forEach((item, i) => {
    // 拿到当前选择的项目
    const selectedArr = getSelectedArr(specs)
    // 遍历每一个按钮
    item.values.forEach(val => {
      if (!val.selected) {
        selectedArr[i] = val.name
        // 去掉undefined之后组合成key
        const key = selectedArr.filter(value => value).join(spliter)
        val.disabled = !pathMap[key]
      }
    })
  })
}


export default {
  name: 'XtxGoodSku',
  props: {
    // specs:所有的规格信息  skus:所有的sku组合
    goods: {
      type: Object,
      default: () => ({ specs: [], skus: [] })
    }
  },
  emits: ['change'],
  setup(props, { emit }) {
    let pathMap = {}
    watchEffect(() => {
      // 得到所有字典集合
      pathMap = getPathMap(props.goods.skus)
      // 组件初始化的时候更新禁用状态
      initDisabledStatus(props.goods.specs, pathMap)
    })

    const clickSpecs = (item, val) => {
      if (val.disabled) return false
      // 选中与取消选中逻辑
      if (val.selected) {
        val.selected = false
      } else {
        item.values.forEach(bv => { bv.selected = false })
        val.selected = true
      }
      // 点击之后再次更新选中状态
      updateDisabledStatus(props.goods.specs, pathMap)
      // 把选择的sku信息传出去给父组件
      // 触发change事件将sku数据传递出去
      const selectedArr = getSelectedArr(props.goods.specs).filter(value => value)
      // 如果选中得规格数量和传入得规格总数相等则传出完整信息(都选择了)
      // 否则传出空对象
      if (selectedArr.length === props.goods.specs.length) {
        // 从路径字典中得到skuId
        const skuId = pathMap[selectedArr.join(spliter)][0]
        const sku = props.goods.skus.find(sku => sku.id === skuId)
        // 传递数据给父组件
        emit('change', {
          skuId: sku.id,
          price: sku.price,
          oldPrice: sku.oldPrice,
          inventory: sku.inventory,
          specsText: sku.specs.reduce((p, n) => `${p} ${n.name}${n.valueName}`, '').trim()
        })
      } else {
        emit('change', {})
      }
    }
    return { clickSpecs }
  }
}
</script>

<style scoped lang="scss">
@mixin sku-state-mixin {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;

  &.selected {
    border-color: $xtxColor;
  }

  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}

.goods-sku {
  padding-left: 10px;
  padding-top: 20px;

  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;

    dt {
      width: 50px;
      color: #999;
    }

    dd {
      flex: 1;
      color: #666;

      >img {
        width: 50px;
        height: 50px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }

      >span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }
    }
  }
}
</style>
//power-set.js
export default function bwPowerSet (originalSet) {
  const subSets = []

  // We will have 2^n possible combinations (where n is a length of original set).
  // It is because for every element of original set we will decide whether to include
  // it or not (2 options for each set element).
  const numberOfCombinations = 2 ** originalSet.length

  // Each number in binary representation in a range from 0 to 2^n does exactly what we need:
  // it shows by its bits (0 or 1) whether to include related element from the set or not.
  // For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to
  // include only "2" to the current set.
  for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
    const subSet = []

    for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {
      // Decide whether we need to include current element into the subset or not.
      if (combinationIndex & (1 << setElementIndex)) {
        subSet.push(originalSet[setElementIndex])
      }
    }

    // Add current subset to the list of all subsets.
    subSets.push(subSet)
  }

  return subSets
}

我们在Detail/index.vue中使用这个三方组件

引入,使用,传数据,相关代码如下:

import XtxSku from '@/components/XtxSku.index.vue'

<!-- sku组件 -->
<XtxSku :goods="goods" />

在这里插入图片描述

给组件绑定一个时间,查看sku对象,选中一个规格是空对象,选中两个规格不是空对象

const skuChange = (sku) => {
    console.log(sku)
}

<!-- sku组件 -->
<XtxSku :goods="goods" @change="skuChange"/>

在这里插入图片描述

8. 通用组件统一注册为全局组件

步骤:把components目录下的所有组件进行全局注册,在main.js中注册插件

//@/components/index.js
// 把components中的所组件都进行全局化注册
// 通过插件的方式
import ImageView from './ImageView/index.vue'
import Sku from './XtxSku/index.vue'
export const componentPlugin = {
  install (app) {
    // app.component('组件名字',组件配置对象)
    app.component('XtxImageView', ImageView)
    app.component('XtxSku', Sku)
  }
}
//main.js

// 引入全局组件插件
import { componentPlugin } from '@/components'

app.use(componentPlugin)

小结

Day04 结束
老是写bug真是困扰emmm
笔记上的代码不太全,和视频有的都对不上emmm

祝大家学习顺利
love and peace在这里插入图片描述

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

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

相关文章

【Git】Git学习-12:关联本地仓库和远程仓库

学习视频链接&#xff1a;【GeekHour】一小时Git教程_哔哩哔哩_bilibili​编辑https://www.bilibili.com/video/BV1HM411377j/?vd_source95dda35ac10d1ae6785cc7006f365780 在github上建立仓库 根据指引将本地仓库push到github上 git remote add origin gitgithub.com:JVZO/f…

【STL专题】深入探索C++之std::string:不止于字符串【万字详解】

欢迎来到CILMY23的博客 &#x1f3c6;本篇主题为&#xff1a;深入探索C之std::string&#xff1a;不止于字符串 &#x1f3c6;个人主页&#xff1a;CILMY23-CSDN博客 &#x1f3c6;系列专栏&#xff1a;Python | C | C语言 | 数据结构与算法 | 贪心算法 | Linux &#x1f3…

一阶数字高通滤波器

本文的主要内容包含一阶高通滤波器公式的推导和数字算法的实现以及编程和仿真 1 计算公式推导 1.1.2 算法实现及仿真 利用python实现的代码如下&#xff1a; import numpy as np # from scipy.signal import butter, lfilter, freqz import matplotlib.pyplot as plt #2pifW…

网站工作原理

web发展史 1.0时代不可修改 2.0可修改&#xff0c;比如发微博 有以下问题&#xff1a; 课程2&#xff1a; 静态页面 html 动态页面 php 经过服务端的语言解释器&#xff0c;解析成html文件&#xff0c;剩下的就和静态流程一样 后面三个是web服务器&#xff0c;语言解释器&…

二、使用Django创建一个基础应用

职位管理系统 - 建模 职位名称类别工作地点职位职责职位要求发布人发布日期修改日期 安装django pip install django5.0查看django版本 python -m django --version创建项目 django-admin startproject recruitment启动服务 python manage.py runserver 0.0.0.0:8000创建…

web APIs总结(3)

1. 本地存储介绍&#xff08;重点&#xff09; 数据存储在用户浏览器中设置、读取方便、甚至页面刷新不丢失数据容量较大&#xff0c;sessionStorage和localStorage约 5M 左右 本地存储分类- localStorage 作用: 可以将数据永久存储在本地(用户的电脑), 除非手动删除&#x…

网络编程—— Http的Get请求

http: hyper text transport protocal:超文本传输协议。 http是一种基于客户端-服务器模式的协议(Client-Server)。它规定只能由客户端先发起请求给服务器&#xff0c; 服务器做出响应。 http数据传输以数据报文的形式进行&#xff0c; 客户端向服务器发起的请求叫做请求报文。…

burpsuite抓包响应报文乱码

1、响应报文中的中文信息乱码 2、解决办法 3、设置成功后重新发起请求

无线网络安全技术基础

无线网络安全技术基础 无线网络安全风险和隐患 随着无线网络技术广泛应用,其安全性越来越引起关注.无线网络的安全主要有访问控制和数据加密,访问控制保证机密数据只能由授权用户访问,而数据加密则要求发送的数据只能被授权用户所接受和使用。 无线网络在数据传输时以微波进…

七大医用耗材启动!如何用数屿医械查询医用耗材中标?

近日&#xff0c;国家医保局发布《关于加强区域协同做好2024年医药集中采购提质扩面的通知》&#xff0c;标志着我国医药集中采购进入新阶段&#xff0c;将实现更高效、更规范的采购模式。 医用耗材是指经药品监督管理部门批准使用的&#xff0c;在诊断、治疗、防护和康复等医疗…

AI代理的类型、优势及示例

AI 代理的类型、优势和示例 AI 代理是重塑商业动态的关键技术进步。了解这些代理的运作方式&#xff0c;发现它们的关键优势包括效率、可扩展性和成本效益。我们将探索代理的实例及它们在各领域的应用&#xff0c;为未来的人工智能趋势和对客户体验的影响铺平道路。 想象一支由…

基于粒子群算法优化的长短期记忆神经网络(PSO-LSTM)回归预测

粒子群算法优化的长短期记忆&#xff08;LSTM&#xff09;神经网络用于回归预测是一种结合了进化计算和深度学习的强大方法。 1. 背景介绍 LSTM神经网络 LSTM&#xff08;Long Short-Term Memory&#xff09;是一种特殊的递归神经网络&#xff08;RNN&#xff09;&#xff0c…

AS连接MUMU模拟器

1、下载安装并打开mumu模拟器 mumu模拟器要弄成开发者模式 点击几次这个版本号&#xff0c;会有提示的&#xff0c;变成开发者模式之后&#xff0c;再连接As 2、打开as 打开Terminal窗口 先要cd 进去自己安装的sdk的platform-tools目录下 cd D:\Android\SDK\platform-tools 尝…

拓展类型——枚举

枚举的作用 枚举通常用来约定某个变量的取值范围 使用字面量和联合类型也可以达到约束变量的作用&#xff0c;但是会有不方便的情况 使用字面量和联合类型约束变量的问题 逻辑含义和真实的值会产生混淆&#xff0c;如果修改了真实值&#xff0c;会造成大量代码需要修改 例&…

大猿人话费平台对接程序,仅支持Windows

1、基础参数 输入大猿人系统分配的相关信息&#xff0c;然后保存。 软件运行在左下角显示在平台的余额。 本软件仅会在本地保存您填写的数据。 且您填写的数据仅会在和您的服务器通讯&#xff0c;不会发往其他地方。 请妥善保存好您的数据。 使用本软件造成的一切和本软件…

618哪些好物值得入手?必备数码好物清单分享

618购物节又来了!一大波智能好物来袭!随着科技的日新月异&#xff0c;智能产品已成为我们生活中不可或缺的一部分&#xff0c;它们不仅炫酷&#xff0c;还能让你生活更便捷。想知道今年都有哪些黑科技新品吗?赶紧跟我们一起&#xff0c;我们将详细介绍这些热门好物。一堆超炫酷…

【学习笔记】后端(Ⅰ)—— NodeJS(Ⅰ)

NodeJS 1、概述 1.1、NodeJS是什么 1.2、NodeJS的主要作用 1.3、NodeJS的优点 1.4、NodeJS 与 浏览器 的 JavaScript 对比 1.4.1 ECMAScript 介绍 1.4.2 JavaScript 介绍 1.4.3 TypeScript 介绍2、基础篇 2.1、Buff…

【Python脚本随手笔记】-- 将 “庆余年2” 等信息写入 Txt 文件中

&#x1f48c; 所属专栏&#xff1a;【Python脚本随手笔记】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#…

Gerchberg-Saxton (GS) 和混合输入输出(Hybrid Input-Output, HIO)算法

文章目录 1. 简介2. 算法描述3. 混合输入输出&#xff08;Hybrid Input-Output, HIO&#xff09;算法3.1 HIO算法步骤3.2 HIO算法的优势3.3 算法描述 4. 算法实现与对比5. 总结参考文献 1. 简介 Gerchberg-Saxton (GS) 算法是一种常用于相位恢复和光学成像的迭代算法。该算法最…

深度学习-转置卷积

转置卷积 转置卷积&#xff08;Transposed Convolution&#xff09;&#xff0c;也被称为反卷积&#xff08;Deconvolution&#xff09;&#xff0c;是深度学习中的一种操作&#xff0c;特别是在卷积神经网络&#xff08;CNN&#xff09;中。它可以将一个低维度的特征图&#x…