当前位置: 首页 > news >正文

【vue前端项目实战案例】之Vue仿饿了么App

本文将介绍一款仿“饿了么”商家页面的App。该案例是基于 Vue2.0 + Vue Router + webpack + ES6
等技术栈实现的一款外卖类App,适合初学者进行学习。

项目源码下载链接在文章末尾

1 项目概述

该项目是一款仿“饿了么”商家页面的外卖类App,主要有以下功能。

  • 商品导航。
  • 商品列表使用手势上下滑动。
  • 购物车中商品的添加和删除操作。
  • 点击商品查看详情。
  • 商家评价。
  • 商家信息。

1.1 开发环境

首先需要安装Node.js 12以上的版本,因为Node.js中已经继承了NPM,所以无需在单独安装NPM。然后再安装Vue脚手架(Vue-CLI)以及创建项目。
项目的调试使用Google Chrome浏览器的控制台进行,在浏览器中按下F12键,然后单击“切换设备工具栏”,进入移动端的调试界面,可以选择相应的设备进行调试,效果如图1 所示。
在这里插入图片描述
图 1 项目效果图

1.2 项目结构

项目结构如图2所示,其中src文件夹是项目的源文件目录,src文件夹下的项目结构如图3所示。
在这里插入图片描述
图2 项目结构

在这里插入图片描述
图3 src文件夹

项目结构中主要文件说明如下。

  • dist:项目打包后的静态文件存放目录。
  • node_modules:项目依赖管理目录。
  • public:项目的静态文件存放目录,也是本地服务器的根目录。
  • src:项目源文件存放目录。
  • package.json:项目npm配置文件。

src文件夹目录说明如下。

  • assets:静态资源文件存放目。
  • components:公共组件存放目录。
  • router:路由配置文件存放目录。
  • store:状态管理配置存放目录。
  • views:视图组件存放目录。
  • App.vue:项目的根组件。
  • main.js:项目的入口文件。

2 入口文件

项目的入口文件有 index.html、main.js和App.vue三个文件,这些入口文件的具体内容介绍如下。

2.1 项目入口页面

index.html是项目默认的主渲染页面文件,主要用于Vue实例挂载点的声明与DOM渲染。代码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1.0"><link rel="icon" href="<%= BASE_URL %>favicon.ico"><title><%= htmlWebpackPlugin.options.title %></title></head><body><div id="app"></div></body>
</html>

2.2 程序入口文件

main.js是程序的入口文件,主要用于加载各种公共组件和初始化Vue实例。本项目中的路由设置和引用的Vant UI组件库就是在该文件中定义的。代码如下:

import Vue from 'vue'
import App from './App.vue'
import './cube-ui'
import './register'import 'common/stylus/index.styl'Vue.config.productionTip = falsenew Vue({render: h => h(App)
}).$mount('#app')

本项目案例使用了 Cube UI 组件库,在项目src目录下创建 cube-ui.js 文件,用于引入项目中要用到的组件,代码如下:

import Vue from 'vue'
import {Style,TabBar,Popup,Dialog,Scroll,Slide,ScrollNav,ScrollNavBar
} from 'cube-ui'Vue.use(TabBar)
Vue.use(Popup)
Vue.use(Dialog)
Vue.use(Scroll)
Vue.use(Slide)
Vue.use(ScrollNav)
Vue.use(ScrollNavBar)

2.3 组件入口文件

App.vue是项目的根组件,所有的页面都是在App.vue下面切换的,所有的页面组件都是App.vue的子组件。在App.vue组件内只需要使用 组件作为占位符,就可以实现各个页面的引入。代码如下:

<template><div id="app" @touchmove.prevent><v-header :seller="seller"></v-header><div class="tab-wrapper"><tab :tabs="tabs"></tab></div></div>
</template><script>import qs from 'query-string'import { getSeller } from 'api'import VHeader from 'components/v-header/v-header'import Goods from 'components/goods/goods'import Ratings from 'components/ratings/ratings'import Seller from 'components/seller/seller'import Tab from 'components/tab/tab'export default {data() {return {seller: {id: qs.parse(location.search).id}}},computed: {tabs() {return [{label: '商品',component: Goods,data: {seller: this.seller}},{label: '评论',component: Ratings,data: {seller: this.seller}},{label: '商家',component: Seller,data: {seller: this.seller}}]}},created() {this._getSeller()},methods: {_getSeller() {getSeller({id: this.seller.id}).then((seller) => {this.seller = Object.assign({}, this.seller, seller)})}},components: {Tab,VHeader}}
</script><style lang="stylus" scoped>#app.tab-wrapperposition: fixedtop: 136pxleft: 0right: 0bottom: 0
</style>

3 项目组件

项目中所有页面组件都在views文件夹中定义,具体组件内容介绍如下。

3.1 头部组件

头部组件主要展示商家的基本信息,如图4所示。
在这里插入图片描述
图 4 头部组件效果

代码如下:

<template><div class="header" @click="showDetail"><div class="content-wrapper"><div class="avatar"><img width="64" height="64" :src="seller.avatar"></div><div class="content"><div class="title"><span class="brand"></span><span class="name">{{seller.name}}</span></div><div class="description">{{seller.description}}/{{seller.deliveryTime}}分钟送达</div><div v-if="seller.supports" class="support"><support-ico :size=1 :type="seller.supports[0].type"></support-ico><span class="text">{{seller.supports[0].description}}</span></div></div><div v-if="seller.supports" class="support-count"><span class="count">{{seller.supports.length}}个</span><i class="icon-keyboard_arrow_right"></i></div></div><div class="bulletin-wrapper"><span class="bulletin-title"></span><span class="bulletin-text">{{seller.bulletin}}</span><i class="icon-keyboard_arrow_right"></i></div><div class="background"><img :src="seller.avatar" width="100%" height="100%"></div></div>
</template><script type="text/ecmascript-6">import SupportIco from 'components/support-ico/support-ico'export default {name: 'v-header',props: {seller: {type: Object,default() {return {}}}},methods: {showDetail() {this.headerDetailComp = this.headerDetailComp || this.$createHeaderDetail({$props: {seller: 'seller'}})this.headerDetailComp.show()}},components: {SupportIco}}
</script><style lang="stylus" rel="stylesheet/stylus">@import "~common/stylus/mixin"@import "~common/stylus/variable".headerposition: relativeoverflow: hiddencolor: $color-whitebackground: $color-background-ss.content-wrapperposition: relativedisplay: flexalign-items: centerpadding: 24px 12px 18px 24px.avatarflex: 0 0 64pxwidth: 64pxmargin-right: 16pximgborder-radius: 2px.contentflex: 1.titledisplay: flexalign-items: centermargin-bottom: 8px.brandwidth: 30pxheight: 18pxbg-image('brand')background-size: 30px 18pxbackground-repeat: no-repeat.namemargin-left: 6pxfont-size: $fontsize-largefont-weight: bold.descriptionmargin-bottom: 8pxline-height: 12pxfont-size: $fontsize-small.supportdisplay: flexalign-items: center.support-icomargin-right: 4px.textline-height: 12pxfont-size: $fontsize-small-s.support-countposition: absoluteright: 12pxbottom: 14pxdisplay: flexalign-items: centerpadding: 0 8pxheight: 24pxline-height: 24pxtext-align: centerborder-radius: 14pxbackground: $color-background-sss.countfont-size: $fontsize-small-s.icon-keyboard_arrow_rightmargin-left: 2pxline-height: 24pxfont-size: $fontsize-small-s.bulletin-wrapperposition: relativedisplay: flexalign-items: centerheight: 28pxline-height: 28pxpadding: 0 8pxbackground: $color-background-sss.bulletin-titleflex: 0 0 22pxwidth: 22pxheight: 12pxmargin-right: 4pxbg-image('bulletin')background-size: 22px 12pxbackground-repeat: no-repeat.bulletin-textflex: 1white-space: nowrapoverflow: hiddentext-overflow: ellipsisfont-size: $fontsize-small-s.icon-keyboard_arrow_rightflex: 0 0 10pxwidth: 10pxfont-size: $fontsize-small-s.backgroundposition: absolutetop: 0left: 0width: 100%height: 100%z-index: -1filter: blur(10px)
</style>

3.2 商品标签栏与侧边导航组件

在商家信息下方,通过商品标签栏实现商品、评价和商家信息的切换,在商品标签中,通过侧边导航实现对商品列表的滚动和分类展示等功能。效果如图5所示。

在这里插入图片描述
图 5 商品标签栏效果

代码如下:

<template><div class="tab"><cube-tab-bar:useTransition=false:showSlider=truev-model="selectedLabel":data="tabs"ref="tabBar"class="border-bottom-1px"></cube-tab-bar><div class="slide-wrapper"><cube-slide:loop=false:auto-play=false:show-dots=false:initial-index="index"ref="slide":options="slideOptions"@scroll="onScroll"@change="onChange"><cube-slide-item v-for="(tab,index) in tabs" :key="index"><component ref="component" :is="tab.component" :data="tab.data"></component></cube-slide-item></cube-slide></div></div>
</template><script>export default {name: 'tab',props: {tabs: {type: Array,default() {return []}},initialIndex: {type: Number,default: 0}},data() {return {index: this.initialIndex,slideOptions: {listenScroll: true,probeType: 3,directionLockThreshold: 0}}},computed: {selectedLabel: {get() {return this.tabs[this.index].label},set(newVal) {this.index = this.tabs.findIndex((value) => {return value.label === newVal})}}},mounted() {this.onChange(this.index)},methods: {onScroll(pos) {const tabBarWidth = this.$refs.tabBar.$el.clientWidthconst slideWidth = this.$refs.slide.slide.scrollerWidthconst transform = -pos.x / slideWidth * tabBarWidththis.$refs.tabBar.setSliderTransform(transform)},onChange(current) {this.index = currentconst instance = this.$refs.component[current]if (instance && instance.fetch) {instance.fetch()}}}}
</script><style lang="stylus" scoped>@import "~common/stylus/variable".tabdisplay: flexflex-direction: columnheight: 100%>>> .cube-tabpadding: 10px 0.slide-wrapperflex: 1overflow: hidden
</style>

3.3 购物车组件

在购物车组件中,当没有任何商品的情况下,无法直接选择,效果如图6所示。当选择商品后,购物车将被激活,效果如图7所示。
在这里插入图片描述
图 6 购物车默认状态

在这里插入图片描述
图 7 选择商品后的状态

当点击购物车图标后,将显示用户选中的商品,效果如图8所示,在购物车商品列表页面中可以对商品进行加减操作,也可以直接清空购物车。
在这里插入图片描述
图8 购物车商品列表

当点击“去结算”按钮时,将弹出购买商品花费的金额提示对话框,效果如图9所示。
在这里插入图片描述
图9 提示对话框

具体实现的代码如下。
商品购物车组件 shop-cart.vue 文件代码如下:

<template><div><div class="shopcart"><div class="content" @click="toggleList"><div class="content-left"><div class="logo-wrapper"><div class="logo" :class="{'highlight':totalCount>0}"><i class="icon-shopping_cart" :class="{'highlight':totalCount>0}"></i></div><div class="num" v-show="totalCount>0"><bubble :num="totalCount"></bubble></div></div><div class="price" :class="{'highlight':totalPrice>0}">¥{{totalPrice}}</div><div class="desc">另需配送费¥{{deliveryPrice}}元</div></div><div class="content-right" @click="pay"><div class="pay" :class="payClass">{{payDesc}}</div></div></div><div class="ball-container"><div v-for="(ball,index) in balls" :key="index"><transition@before-enter="beforeDrop"@enter="dropping"@after-enter="afterDrop"><div class="ball" v-show="ball.show"><div class="inner inner-hook"></div></div></transition></div></div></div></div>
</template><script>import Bubble from 'components/bubble/bubble'const BALL_LEN = 10const innerClsHook = 'inner-hook'function createBalls() {let balls = []for (let i = 0; i < BALL_LEN; i++) {balls.push({show: false})}return balls}export default {name: 'shop-cart',props: {selectFoods: {type: Array,default() {return []}},deliveryPrice: {type: Number,default: 0},minPrice: {type: Number,default: 0},sticky: {type: Boolean,default: false},fold: {type: Boolean,default: true}},data() {return {balls: createBalls(),listFold: this.fold}},created() {this.dropBalls = []},computed: {totalPrice() {let total = 0this.selectFoods.forEach((food) => {total += food.price * food.count})return total},totalCount() {let count = 0this.selectFoods.forEach((food) => {count += food.count})return count},payDesc() {if (this.totalPrice === 0) {return `${this.minPrice}元起送`} else if (this.totalPrice < this.minPrice) {let diff = this.minPrice - this.totalPricereturn `还差¥${diff}元起送`} else {return '去结算'}},payClass() {if (!this.totalCount || this.totalPrice < this.minPrice) {return 'not-enough'} else {return 'enough'}}},methods: {toggleList() {if (this.listFold) {if (!this.totalCount) {return}this.listFold = falsethis._showShopCartList()this._showShopCartSticky()} else {this.listFold = truethis._hideShopCartList()}},pay(e) {if (this.totalPrice < this.minPrice) {return}this.$createDialog({title: '支付',content: `您需要支付${this.totalPrice}`}).show()e.stopPropagation()},drop(el) {for (let i = 0; i < this.balls.length; i++) {const ball = this.balls[i]if (!ball.show) {ball.show = trueball.el = elthis.dropBalls.push(ball)return}}},beforeDrop(el) {const ball = this.dropBalls[this.dropBalls.length - 1]const rect = ball.el.getBoundingClientRect()const x = rect.left - 32const y = -(window.innerHeight - rect.top - 22)el.style.display = ''el.style.transform = el.style.webkitTransform = `translate3d(0,${y}px,0)`const inner = el.getElementsByClassName(innerClsHook)[0]inner.style.transform = inner.style.webkitTransform = `translate3d(${x}px,0,0)`},dropping(el, done) {this._reflow = document.body.offsetHeightel.style.transform = el.style.webkitTransform = `translate3d(0,0,0)`const inner = el.getElementsByClassName(innerClsHook)[0]inner.style.transform = inner.style.webkitTransform = `translate3d(0,0,0)`el.addEventListener('transitionend', done)},afterDrop(el) {const ball = this.dropBalls.shift()if (ball) {ball.show = falseel.style.display = 'none'}},_showShopCartList() {this.shopCartListComp = this.shopCartListComp || this.$createShopCartList({$props: {selectFoods: 'selectFoods'},$events: {leave: () => {this._hideShopCartSticky()},hide: () => {this.listFold = true},add: (el) => {this.shopCartStickyComp.drop(el)}}})this.shopCartListComp.show()},_showShopCartSticky() {this.shopCartStickyComp = this.shopCartStickyComp || this.$createShopCartSticky({$props: {selectFoods: 'selectFoods',deliveryPrice: 'deliveryPrice',minPrice: 'minPrice',fold: 'listFold',list: this.shopCartListComp}})this.shopCartStickyComp.show()},_hideShopCartList() {const list = this.sticky ? this.$parent.list : this.shopCartListComplist.hide && list.hide()},_hideShopCartSticky() {this.shopCartStickyComp.hide()}},watch: {fold(newVal) {this.listFold = newVal},totalCount(count) {if (!this.fold && count === 0) {this._hideShopCartList()}}},components: {Bubble}}
</script><style lang="stylus" scoped>@import "~common/stylus/mixin"@import "~common/stylus/variable".shopcartheight: 100%.contentdisplay: flexbackground: $color-backgroundfont-size: 0color: $color-light-grey.content-leftflex: 1.logo-wrapperdisplay: inline-blockvertical-align: topposition: relativetop: -10pxmargin: 0 12pxpadding: 6pxwidth: 56pxheight: 56pxbox-sizing: border-boxborder-radius: 50%background: $color-background.logowidth: 100%height: 100%border-radius: 50%text-align: centerbackground: $color-dark-grey&.highlightbackground: $color-blue.icon-shopping_cartline-height: 44pxfont-size: $fontsize-large-xxxcolor: $color-light-grey&.highlightcolor: $color-white.numposition: absolutetop: 0right: 0.pricedisplay: inline-blockvertical-align: topmargin-top: 12pxline-height: 24pxpadding-right: 12pxbox-sizing: border-boxborder-right: 1px solid rgba(255, 255, 255, 0.1)font-weight: 700font-size: $fontsize-large&.highlightcolor: $color-white.descdisplay: inline-blockvertical-align: topmargin: 12px 0 0 12pxline-height: 24pxfont-size: $fontsize-small-s.content-rightflex: 0 0 105pxwidth: 105px.payheight: 48pxline-height: 48pxtext-align: centerfont-weight: 700font-size: $fontsize-small&.not-enoughbackground: $color-dark-grey&.enoughbackground: $color-greencolor: $color-white.ball-container.ballposition: fixedleft: 32pxbottom: 22pxz-index: 200transition: all 0.4s cubic-bezier(0.49, -0.29, 0.75, 0.41).innerwidth: 16pxheight: 16pxborder-radius: 50%background: $color-bluetransition: all 0.4s linear
</style>

商品购物车列表组件 shop-cart-list.vue 文件代码如下:

<template><transition name="fade"><cube-popup:mask-closable=truev-show="visible"@mask-click="maskClick"position="bottom"type="shop-cart-list":z-index=90><transitionname="move"@after-leave="afterLeave"><div v-show="visible"><div class="list-header"><h1 class="title">购物车</h1><span class="empty" @click="empty">清空</span></div><cube-scroll class="list-content" ref="listContent"><ul><liclass="food"v-for="(food,index) in selectFoods":key="index"><span class="name">{{food.name}}</span><div class="price"><span>¥{{food.price*food.count}}</span></div><div class="cart-control-wrapper"><cart-control @add="onAdd" :food="food"></cart-control></div></li></ul></cube-scroll></div></transition></cube-popup></transition>
</template><script>import CartControl from 'components/cart-control/cart-control'import popupMixin from 'common/mixins/popup'const EVENT_SHOW = 'show'const EVENT_ADD = 'add'const EVENT_LEAVE = 'leave'export default {name: 'shop-cart-list',mixins: [popupMixin],props: {selectFoods: {type: Array,default() {return []}}},created() {this.$on(EVENT_SHOW, () => {this.$nextTick(() => {this.$refs.listContent.refresh()})})},methods: {onAdd(target) {this.$emit(EVENT_ADD, target)},afterLeave() {this.$emit(EVENT_LEAVE)},maskClick() {this.hide()},empty() {this.dialogComp = this.$createDialog({type: 'confirm',content: '清空购物车?',$events: {confirm: () => {this.selectFoods.forEach((food) => {food.count = 0})this.hide()}}})this.dialogComp.show()}},components: {CartControl}}
</script><style lang="stylus" scoped>@import "~common/stylus/variable".cube-shop-cart-listbottom: 48px&.fade-enter, &.fade-leave-activeopacity: 0&.fade-enter-active, &.fade-leave-activetransition: all .3s ease-in-out.move-enter, .move-leave-activetransform: translate3d(0, 100%, 0).move-enter-active, .move-leave-activetransition: all .3s ease-in-out.list-headerheight: 40pxline-height: 40pxpadding: 0 18pxbackground: $color-background-ssss.titlefloat: leftfont-size: $fontsize-mediumcolor: $color-dark-grey.emptyfloat: rightfont-size: $fontsize-smallcolor: $color-blue.list-contentpadding: 0 18pxmax-height: 217pxoverflow: hiddenbackground: $color-white.foodposition: relativepadding: 12px 0box-sizing: border-box.nameline-height: 24pxfont-size: $fontsize-mediumcolor: $color-dark-grey.priceposition: absoluteright: 90pxbottom: 12pxline-height: 24pxfont-weight: 700font-size: $fontsize-mediumcolor: $color-red.cart-control-wrapperposition: absoluteright: 0bottom: 6px</style>

3.4 商品列表组件

在商品标签页面中,商品列表主要展示所有商品的信息,可以点击商品卡片右侧的加号添加购物车。效果如图10所示。
在这里插入图片描述
图 10 商品列表效果

代码如下:

<template><div class="goods"><div class="scroll-nav-wrapper"><cube-scroll-nav:side=true:data="goods":options="scrollOptions"v-if="goods.length"><template slot="bar" slot-scope="props"><cube-scroll-nav-bardirection="vertical":labels="props.labels":txts="barTxts":current="props.current"><template slot-scope="props"><div class="text"><support-icov-if="props.txt.type>=1":size=3:type="props.txt.type"></support-ico><span>{{props.txt.name}}</span><span class="num" v-if="props.txt.count"><bubble :num="props.txt.count"></bubble></span></div></template></cube-scroll-nav-bar></template><cube-scroll-nav-panelv-for="good in goods":key="good.name":label="good.name":title="good.name"><ul><li@click="selectFood(food)"v-for="food in good.foods":key="food.name"class="food-item"><div class="icon"><img width="57" height="57" :src="food.icon"></div><div class="content"><h2 class="name">{{food.name}}</h2><p class="desc">{{food.description}}</p><div class="extra"><span class="count">月售{{food.sellCount}}份</span><span>好评率{{food.rating}}%</span></div><div class="price"><span class="now">¥{{food.price}}</span><span class="old" v-show="food.oldPrice">¥{{food.oldPrice}}</span></div><div class="cart-control-wrapper"><cart-control @add="onAdd" :food="food"></cart-control></div></div></li></ul></cube-scroll-nav-panel></cube-scroll-nav></div><div class="shop-cart-wrapper"><shop-cartref="shopCart":select-foods="selectFoods":delivery-price="seller.deliveryPrice":min-price="seller.minPrice"></shop-cart></div></div>
</template><script>import { getGoods } from 'api'import CartControl from 'components/cart-control/cart-control'import ShopCart from 'components/shop-cart/shop-cart'import Food from 'components/food/food'import SupportIco from 'components/support-ico/support-ico'import Bubble from 'components/bubble/bubble'export default {name: 'goods',props: {data: {type: Object,default() {return {}}}},data() {return {goods: [],selectedFood: {},scrollOptions: {click: false,directionLockThreshold: 0}}},computed: {seller() {return this.data.seller},selectFoods() {let foods = []this.goods.forEach((good) => {good.foods.forEach((food) => {if (food.count) {foods.push(food)}})})return foods},barTxts() {let ret = []this.goods.forEach((good) => {const {type, name, foods} = goodlet count = 0foods.forEach((food) => {count += food.count || 0})ret.push({type,name,count})})return ret}},methods: {fetch() {if (!this.fetched) {this.fetched = truegetGoods({id: this.seller.id}).then((goods) => {this.goods = goods})}},selectFood(food) {this.selectedFood = foodthis._showFood()this._showShopCartSticky()},onAdd(target) {this.$refs.shopCart.drop(target)},_showFood() {this.foodComp = this.foodComp || this.$createFood({$props: {food: 'selectedFood'},$events: {add: (target) => {this.shopCartStickyComp.drop(target)},leave: () => {this._hideShopCartSticky()}}})this.foodComp.show()},_showShopCartSticky() {this.shopCartStickyComp = this.shopCartStickyComp || this.$createShopCartSticky({$props: {selectFoods: 'selectFoods',deliveryPrice: this.seller.deliveryPrice,minPrice: this.seller.minPrice,fold: true}})this.shopCartStickyComp.show()},_hideShopCartSticky() {this.shopCartStickyComp.hide()}},components: {Bubble,SupportIco,CartControl,ShopCart,Food}}
</script><style lang="stylus" scoped>@import "~common/stylus/mixin"@import "~common/stylus/variable".goodsposition: relativetext-align: leftheight: 100%.scroll-nav-wrapperposition: absolutewidth: 100%top: 0left: 0bottom: 48px>>> .cube-scroll-nav-barwidth: 80pxwhite-space: normaloverflow: hidden>>> .cube-scroll-nav-bar-itempadding: 0 10pxdisplay: flexalign-items: centerheight: 56pxline-height: 14pxfont-size: $fontsize-smallbackground: $color-background-ssss.textflex: 1position: relative.numposition: absoluteright: -8pxtop: -10px.support-icodisplay: inline-blockvertical-align: topmargin-right: 4px>>> .cube-scroll-nav-bar-item_activebackground: $color-whitecolor: $color-dark-grey>>> .cube-scroll-nav-panel-titlepadding-left: 14pxheight: 26pxline-height: 26pxborder-left: 2px solid $color-col-linefont-size: $fontsize-smallcolor: $color-greybackground: $color-background-ssss.food-itemdisplay: flexmargin: 18pxpadding-bottom: 18pxposition: relative&:last-childborder-none()margin-bottom: 0.iconflex: 0 0 57pxmargin-right: 10pximgheight: auto.contentflex: 1.namemargin: 2px 0 8px 0height: 14pxline-height: 14pxfont-size: $fontsize-mediumcolor: $color-dark-grey.desc, .extraline-height: 10pxfont-size: $fontsize-small-scolor: $color-light-grey.descline-height: 12pxmargin-bottom: 8px.extra.countmargin-right: 12px.pricefont-weight: 700line-height: 24px.nowmargin-right: 8pxfont-size: $fontsize-mediumcolor: $color-red.oldtext-decoration: line-throughfont-size: $fontsize-small-scolor: $color-light-grey.cart-control-wrapperposition: absoluteright: 0bottom: 12px.shop-cart-wrapperposition: absoluteleft: 0bottom: 0z-index: 50width: 100%height: 48px
</style>

3.5 商家公告组件

点击头部区域,会弹出商家公告的详细内容,效果如图11所示。
在这里插入图片描述
图11 商家公告内容

代码如下:

<template><transition name="fade"><div v-show="visible" class="header-detail" @touchmove.stop.prevent><div class="detail-wrapper clear-fix"><div class="detail-main"><h1 class="name">{{seller.name}}</h1><div class="star-wrapper"><star :size="48" :score="seller.score"></star></div><div class="title"><div class="line"></div><div class="text">优惠信息</div><div class="line"></div></div><ul v-if="seller.supports" class="supports"><li class="support-item" v-for="(item,index) in seller.supports" :key="item.id"><support-ico :size=2 :type="seller.supports[index].type"></support-ico><span class="text">{{seller.supports[index].description}}</span></li></ul><div class="title"><div class="line"></div><div class="text">商家公告</div><div class="line"></div></div><div class="bulletin"><p class="content">{{seller.bulletin}}</p></div></div></div><div class="detail-close" @click="hide"><i class="icon-close"></i></div></div></transition>
</template><script>import popupMixin from 'common/mixins/popup'import Star from 'components/star/star'import SupportIco from 'components/support-ico/support-ico'export default {name: 'header-detail',mixins: [popupMixin],props: {seller: {type: Object,default() {return {}}}},components: {SupportIco,Star}}
</script><style lang="stylus" scoped>@import "~common/stylus/mixin"@import "~common/stylus/variable".header-detailposition: fixedz-index: 100top: 0left: 0width: 100%height: 100%overflow: autobackdrop-filter: blur(10px)opacity: 1color: $color-whitebackground: $color-background-s&.fade-enter-active, &.fade-leave-activetransition: all 0.5s&.fade-enter, &.fade-leave-activeopacity: 0background: $color-background.detail-wrapperdisplay: inline-blockwidth: 100%min-height: 100%.detail-mainmargin-top: 64pxpadding-bottom: 64px.nameline-height: 16pxtext-align: centerfont-size: $fontsize-largefont-weight: 700.star-wrappermargin-top: 18pxpadding: 2px 0text-align: center.titledisplay: flexwidth: 80%margin: 28px auto 24px auto.lineflex: 1position: relativetop: -6pxborder-bottom: 1px solid rgba(255, 255, 255, 0.2).textpadding: 0 12pxfont-weight: 700font-size: $fontsize-medium.supportswidth: 80%margin: 0 auto.support-itemdisplay: flexalign-items: centerpadding: 0 12pxmargin-bottom: 12px&:last-childmargin-bottom: 0.support-icomargin-right: 6px.textline-height: 16pxfont-size: $fontsize-small.bulletinwidth: 80%margin: 0 auto.contentpadding: 0 12pxline-height: 24pxfont-size: $fontsize-small.detail-closeposition: relativewidth: 30pxheight: 30pxmargin: -64px auto 0 autoclear: bothfont-size: $fontsize-large-xxxx
</style>

3.6 评价内容组件

在商家评价内容的组件中,共有两个组成部分,一个是商家的评分组件,效果如图12所示;另一个是评价列表内容,效果如图13所示。
在这里插入图片描述
图 12 评分组件效果

在这里插入图片描述
图 13 评价列表效果

商家评分组件 ratings.vue 文件代码如下:

<template><cube-scroll ref="scroll" class="ratings" :options="scrollOptions"><div class="ratings-content"><div class="overview"><div class="overview-left"><h1 class="score">{{seller.score}}</h1><div class="title">综合评分</div><div class="rank">高于周边商家{{seller.rankRate}}%</div></div><div class="overview-right"><div class="score-wrapper"><span class="title">服务态度</span><star :size="36" :score="seller.serviceScore"></star><span class="score">{{seller.serviceScore}}</span></div><div class="score-wrapper"><span class="title">商品评分</span><star :size="36" :score="seller.foodScore"></star><span class="score">{{seller.foodScore}}</span></div><div class="delivery-wrapper"><span class="title">送达时间</span><span class="delivery">{{seller.deliveryTime}}分钟</span></div></div></div><split></split><rating-select@select="onSelect"@toggle="onToggle":selectType="selectType":onlyContent="onlyContent":ratings="ratings"></rating-select><div class="rating-wrapper"><ul><liv-for="(rating,index) in computedRatings":key="index"class="rating-item border-bottom-1px"><div class="avatar"><img width="28" height="28" :src="rating.avatar"></div><div class="content"><h1 class="name">{{rating.username}}</h1><div class="star-wrapper"><star :size="24" :score="rating.score"></star><span class="delivery" v-show="rating.deliveryTime">{{rating.deliveryTime}}</span></div><p class="text">{{rating.text}}</p><div class="recommend" v-show="rating.recommend && rating.recommend.length"><span class="icon-thumb_up"></span><spanclass="item"v-for="(item,index) in rating.recommend":key="index">{{item}}</span></div><div class="time">{{format(rating.rateTime)}}</div></div></li></ul></div></div></cube-scroll>
</template><script>import Star from 'components/star/star'import RatingSelect from 'components/rating-select/rating-select'import Split from 'components/split/split'import ratingMixin from 'common/mixins/rating'import { getRatings } from 'api'import moment from 'moment'export default {name: 'ratings',mixins: [ratingMixin],props: {data: {type: Object}},data () {return {ratings: [],scrollOptions: {click: false,directionLockThreshold: 0}}},computed: {seller () {return this.data.seller || {}}},methods: {fetch () {if (!this.fetched) {this.fetched = truegetRatings({id: this.seller.id}).then((ratings) => {this.ratings = ratings})}},format (time) {return moment(time).format('YYYY-MM-DD hh:mm')}},components: {Star,Split,RatingSelect},watch: {selectType () {this.$nextTick(() => {this.$refs.scroll.refresh()})}}}
</script><style lang="stylus" scoped>@import "~common/stylus/variable"@import "~common/stylus/mixin".ratingsposition: relativetext-align: leftwhite-space: normalheight: 100%.overviewdisplay: flexpadding: 18px 0.overview-leftflex: 0 0 137pxpadding: 6px 0width: 137pxborder-right: 1px solid $color-col-linetext-align: center@media only screen and (max-width: 320px)flex: 0 0 120pxwidth: 120px.scoremargin-bottom: 6pxline-height: 28pxfont-size: $fontsize-large-xxxcolor: $color-orange.titlemargin-bottom: 8pxline-height: 12pxfont-size: $fontsize-smallcolor: $color-dark-grey.rankline-height: 10pxfont-size: $fontsize-small-scolor: $color-light-grey.overview-rightflex: 1padding: 6px 0 6px 24px@media only screen and (max-width: 320px)padding-left: 6px.score-wrapperdisplay: flexalign-items: centermargin-bottom: 8px.titleline-height: 18pxfont-size: $fontsize-smallcolor: $color-dark-grey.starmargin: 0 12px.scoreline-height: 18pxfont-size: $fontsize-smallcolor: $color-orange.delivery-wrapperdisplay: flexalign-items: center.titleline-height: 18pxfont-size: $fontsize-smallcolor: $color-dark-grey.deliverymargin-left: 12pxfont-size: $fontsize-smallcolor: $color-light-grey.rating-wrapperpadding: 0 18px.rating-itemdisplay: flexpadding: 18px 0&:last-childborder-none().avatarflex: 0 0 28pxwidth: 28pxmargin-right: 12pximgheight: autoborder-radius: 50%.contentposition: relativeflex: 1.namemargin-bottom: 4pxline-height: 12pxfont-size: $fontsize-small-scolor: $color-dark-grey.star-wrappermargin-bottom: 6pxdisplay: flexalign-items: center.starmargin-right: 6px.deliveryfont-size: $fontsize-small-scolor: $color-light-grey.textmargin-bottom: 8pxline-height: 18pxcolor: $color-dark-greyfont-size: $fontsize-small.recommenddisplay: flexalign-items: centerflex-wrap: wrapline-height: 16px.icon-thumb_up, .itemmargin: 0 8px 4px 0font-size: $fontsize-small-s.icon-thumb_upcolor: $color-blue.itempadding: 0 6pxborder: 1px solid $color-row-lineborder-radius: 1pxcolor: $color-light-greybackground: $color-white.timeposition: absolutetop: 0right: 0line-height: 12pxfont-size: $fontsize-smallcolor: $color-light-grey
</style>

评价内容列表组件 rating-select.vue 文件代码如下:

<template><div class="rating-select"><div class="rating-type border-bottom-1px"><span @click="select(2)" class="block positive" :class="{'active':selectType===2}">{{desc.all}}<spanclass="count">{{ratings.length}}</span></span><span @click="select(0)" class="block positive" :class="{'active':selectType===0}">{{desc.positive}}<spanclass="count">{{positives.length}}</span></span><span @click="select(1)" class="block negative" :class="{'active':selectType===1}">{{desc.negative}}<spanclass="count">{{negatives.length}}</span></span></div><div @click="toggleContent" class="switch" :class="{'on':onlyContent}"><span class="icon-check_circle"></span><span class="text">只看有内容的评价</span></div></div>
</template>
<script>const POSITIVE = 0const NEGATIVE = 1const ALL = 2const EVENT_TOGGLE = 'toggle'const EVENT_SELECT = 'select'export default {props: {ratings: {type: Array,default() {return []}},selectType: {type: Number,default: ALL},onlyContent: {type: Boolean,default: false},desc: {type: Object,default() {return {all: '全部',positive: '满意',negative: '不满意'}}}},computed: {positives() {return this.ratings.filter((rating) => {return rating.rateType === POSITIVE})},negatives() {return this.ratings.filter((rating) => {return rating.rateType === NEGATIVE})}},methods: {select(type) {this.$emit(EVENT_SELECT, type)},toggleContent() {this.$emit(EVENT_TOGGLE)}}}
</script>
<style lang="stylus" rel="stylesheet/stylus">@import "~common/stylus/variable".rating-select.rating-typepadding: 18px 0margin: 0 18px.blockdisplay: inline-blockpadding: 8px 12pxmargin-right: 8pxline-height: 16pxborder-radius: 1pxfont-size: $fontsize-smallcolor: $color-grey&.activecolor: $color-white.countmargin-left: 2px&.positivebackground: $color-light-blue&.activebackground: $color-blue&.negativebackground: $color-light-grey-s&.activebackground: $color-grey.switchdisplay: flexalign-items: centerpadding: 12px 18pxline-height: 24pxborder-bottom: 1px solid $color-row-linecolor: $color-light-grey&.on.icon-check_circlecolor: $color-green.icon-check_circlemargin-right: 4pxfont-size: $fontsize-large-xxx.textfont-size: $fontsize-small
</style>

3.7 商家信息组件

商家信息组件中设计了商家的星级和服务内容,效果如图14所示。

在这里插入图片描述
图 14 商家服务信息效果

以及商家的优惠活动和公告内容。效果如图15所示。

在这里插入图片描述
图15 商家活动公告内容

代码如下:

<template><cube-scroll class="seller" :options="sellerScrollOptions"><div class="seller-content"><div class="overview"><h1 class="title">{{seller.name}}</h1><div class="desc border-bottom-1px"><star :size="36" :score="seller.score"></star><span class="text">({{seller.ratingCount}})</span><span class="text">月售{{seller.sellCount}}单</span></div><ul class="remark"><li class="block"><h2>起送价</h2><div class="content"><span class="stress">{{seller.minPrice}}</span></div></li><li class="block"><h2>商家配送</h2><div class="content"><span class="stress">{{seller.deliveryPrice}}</span></div></li><li class="block"><h2>平均配送时间</h2><div class="content"><span class="stress">{{seller.deliveryTime}}</span>分钟</div></li></ul><div class="favorite" @click="toggleFavorite"><span class="icon-favorite" :class="{'active':favorite}"></span><span class="text">{{favoriteText}}</span></div></div><split></split><div class="bulletin"><h1 class="title">公告与活动</h1><div class="content-wrapper border-bottom-1px"><p class="content">{{seller.bulletin}}</p></div><ul v-if="seller.supports" class="supports"><liclass="support-item border-bottom-1px"v-for="(item,index) in seller.supports":key="index"><support-ico :size=4 :type="seller.supports[index].type"></support-ico><span class="text">{{seller.supports[index].description}}</span></li></ul></div><split></split><div class="pics"><h1 class="title">商家实景</h1><cube-scroll class="pic-wrapper" :options="picScrollOptions"><ul class="pic-list"><li class="pic-item"v-for="(pic,index) in seller.pics":key="index"><img :src="pic" width="120" height="90"></li></ul></cube-scroll></div><split></split><div class="info"><h1 class="title border-bottom-1px">商家信息</h1><ul><liclass="info-item border-bottom-1px"v-for="(info,index) in seller.infos":key="index">{{info}}</li></ul></div></div></cube-scroll>
</template><script>import { saveToLocal, loadFromLocal } from 'common/js/storage'import Star from 'components/star/star'import Split from 'components/split/split'import SupportIco from 'components/support-ico/support-ico'export default {props: {data: {type: Object,default() {return {}}}},data() {return {favorite: false,sellerScrollOptions: {directionLockThreshold: 0,click: false},picScrollOptions: {scrollX: true,stopPropagation: true,directionLockThreshold: 0}}},computed: {seller() {return this.data.seller || {}},favoriteText() {return this.favorite ? '已收藏' : '收藏'}},created() {this.favorite = loadFromLocal(this.seller.id, 'favorite', false)},methods: {toggleFavorite() {this.favorite = !this.favoritesaveToLocal(this.seller.id, 'favorite', this.favorite)}},components: {SupportIco,Star,Split}}
</script><style lang="stylus" scoped>@import "~common/stylus/variable"@import "~common/stylus/mixin".sellerheight: 100%text-align: left.overviewposition: relativepadding: 18px.titlemargin-bottom: 8pxline-height: 14pxfont-size: $fontsize-mediumcolor: $color-dark-grey.descdisplay: flexalign-items: centerpadding-bottom: 18px.starmargin-right: 8px.textmargin-right: 12pxline-height: 18pxfont-size: $fontsize-small-scolor: $color-grey.remarkdisplay: flexpadding-top: 18px.blockflex: 1text-align: centerborder-right: 1px solid $color-col-line&:last-childborder: noneh2margin-bottom: 4pxline-height: 10pxfont-size: $fontsize-small-scolor: $color-light-grey.contentline-height: 24pxfont-size: $fontsize-small-scolor: $color-dark-grey.stressfont-size: $fontsize-large-xxx.favoriteposition: absolutewidth: 50pxright: 11pxtop: 18pxtext-align: center.icon-favoritedisplay: blockmargin-bottom: 4pxline-height: 24pxfont-size: $fontsize-large-xxxcolor: $color-light-grey-s&.activecolor: $color-red.textline-height: 10pxfont-size: $fontsize-small-scolor: $color-grey.bulletinpadding: 18px 18px 0 18pxwhite-space: normal.titlemargin-bottom: 8pxline-height: 14pxcolor: $color-dark-greyfont-size: $fontsize-medium.content-wrapperpadding: 0 12px 16px 12px.contentline-height: 24pxfont-size: $fontsize-smallcolor: $color-red.supports.support-itemdisplay: flexalign-items: centerpadding: 16px 12px&:last-childborder-none().support-icomargin-right: 6px.textline-height: 16pxfont-size: $fontsize-smallcolor: $color-dark-grey.picspadding: 18px.titlemargin-bottom: 12pxline-height: 14pxcolor: $color-dark-greyfont-size: $fontsize-medium.pic-wrapperdisplay: flexalign-items: center.pic-list.pic-itemdisplay: inline-blockmargin-right: 6pxwidth: 120pxheight: 90px&:last-childmargin: 0.infopadding: 18px 18px 0 18pxcolor: $color-dark-grey.titlepadding-bottom: 12pxline-height: 14pxfont-size: $fontsize-medium.info-itempadding: 16px 12pxline-height: 16pxfont-size: $fontsize-small&:last-childborder-none()
</style>

项目源码下载:
https://download.csdn.net/download/p445098355/89570496

相关文章:

【vue前端项目实战案例】之Vue仿饿了么App

本文将介绍一款仿“饿了么”商家页面的App。该案例是基于 Vue2.0 Vue Router webpack ES6 等技术栈实现的一款外卖类App&#xff0c;适合初学者进行学习。 项目源码下载链接在文章末尾 1 项目概述 该项目是一款仿“饿了么”商家页面的外卖类App&#xff0c;主要有以下功能…...

冷热分离——Java全栈知识(36)

之前在面试的时候有老师问&#xff1a; 我看你使用了水平分表&#xff0c;但是如果有些 1%的数据占了访问量的 90%&#xff0c;而剩下 99%的数据只占了访问量的 10%。这种情况怎么处理。 1 、冷热分离 1.1、什么是冷热分离 冷热分离指的是在处理数据时将数据库分为冷库和热库…...

了解Selenium中的WebElement

Selenium中到处都使用WebElement来执行各种操作。什么是WebElement&#xff1f;这篇文章将详细讨论WebElement。 Selenium中的WebElement是一个表示网站HTML元素的Java接口。HTML元素包含一个开始标记和一个结束标记&#xff0c;内容位于这两个标记之间。 HTML元素的重命名 …...

OpenCV facedetect 人脸检测官方示例项目配置

运行程序。该程序会自动打开摄像头&#xff0c;识别并定位摄像头前的人脸以及眼睛部位。 输入q或者Q&#xff0c;退出程序。 或进行文本中所包含的图片路径 或 单个图片进行检测&#xff0c;自行修改代码即可 配置环境项目&#xff0c;debug 解决error C4996: ‘fopen’: This…...

自定义Laravel Artisan风格:打造个性化命令行体验

自定义Laravel Artisan风格&#xff1a;打造个性化命令行体验 引言 Laravel的Artisan命令行工具是开发过程中不可或缺的一部分&#xff0c;它提供了一个强大的接口来执行各种开发、维护、测试等任务。除了执行命令&#xff0c;Artisan还允许开发者自定义命令行输出的风格&…...

CTF之网站被黑

简单看一下网页和源码没发现什么明显漏洞 那就扫描一下目录 发现了/shell.php文件&#xff0c;访问一下&#xff0c;发现是一个后台管理登录页面 别无他法只能爆破喽&#xff0c;爆破后发现密码是hack flag{25891d9e9d377f006eda3ca7d4c34c4d}...

Electron学习笔记(一)基础环境

目录 前言 基础环境准备 安装 Node.js 配置项目文件 通过代理服务安装 通过国内仓库安装 一些常见问题&#xff1a; 前言 一个新手学习Electron的笔记&#xff0c;记录为主&#xff0c;仅供参考。 其他文章见专栏目录。 基础环境准备 开发之前先将基础环境搭建好。 …...

【C语言】栈的实现(数据结构)

前言&#xff1a; 还是举一个生活中的例子&#xff0c;大家都玩过积木&#xff0c;当我们把积木叠起来的时候&#xff0c;如果要拿到最底部的积木&#xff0c;我们必须从顶端一个一个打出&#xff0c;最后才能拿到底部的积木&#xff0c;也就是后进先出&#xff08;先进后出&a…...

前端三大主流框架对比

在现代前端开发中&#xff0c;React、Vue和Angular是三大流行的框架/库。它们各自有独特的优缺点&#xff0c;适用于不同的开发需求和项目规模。下面是对这三者的详细比较&#xff1a; 一、 React 简介&#xff1a; 由Facebook开发和维护&#xff0c;是一个用于构建用户界面…...

AOP~面向切面编程介绍

AOP基础 概述 AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;面向特定方法的编程。 动态代理是面向切面编程最主流的实现。 SpringAOP是Spring框架的高级技术&#xff0c;旨在管理bean对象的过程中&#xff0c…...

Android SurfaceFlinger——GraphicBuffer的提交(三十三)

在 SurfaceFlinger 中,我们 dequeueBuffer 和 queueBuffer 是 Surface 控制接口中非常重要的两个函数,分别用于从 Surface 的 BufferQueue 中取出缓冲区和向 BufferQueue 提交(队列)缓冲区。这两个函数在生产者和消费者模型中扮演着核心角色,确保了图像数据的高效和有序传…...

创维汽车滁州永通体验中心开业仪式暨超充车型区域上市会圆满成功

2024年7月20日&#xff0c;创维汽车滁州永通体验中心盛大开业&#xff0c;当日&#xff0c;创维汽车市场部经理周世鹏、安徽大区总监王大明等领导参加本次开业盛典&#xff0c;共同见证创维汽车滁州永通体验中心成功落地。 2021年&#xff0c;新能源乘用车高速发展&#xff0c;…...

【PHP】系统的登录和注册

一、为什么要学习系统的登录和注册 系统的登录和注册可能存在多种漏洞&#xff0c;这些漏洞可能被恶意攻击者利用&#xff0c;从而对用户的安全和隐私构成威胁。通过学习系统的登录和注册理解整个登录和注册的逻辑方便后续更好站在开发的角度思考问题发现漏洞。以下是一些常见…...

2024.7.29 刷题总结

2024.7.29 **每日一题** 682.棒球比赛&#xff0c;这道题是一道简单的模拟题&#xff0c;用栈模拟题中的四个操作就可以了&#xff0c;操作一是将x加到列表末尾&#xff0c;操作二是将列表的后两项之和加到列表末尾&#xff0c;操作三是把列表最后一项的两倍加到列表末尾&#…...

WebSocket程序设计

协议说明 WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。Websocket主要用在B/S架构的应用程序中&#xff0c;在 WebSocket API 中&#xff0c;浏览器和服务器只…...

ES(ElasticSearch)倒排索引

目录 正排与倒排索引 1.正排索引 作用&#xff1a; 优点&#xff1a; 缺点&#xff1a; 2.倒排索引 原理&#xff1a; 倒排索引的构建流程&#xff1a; 倒排索引的搜索流程&#xff1a; 优点&#xff1a; 缺点&#xff1a; 3. 应用场景 倒排索引中有几个非常重要的概念…...

Android Studio Build窗口出现中文乱码问题

刚安装成功的android studio软件打开工程&#xff0c;编译时下方build窗口中中文是乱码。 解决&#xff1a; 可点击studio状态栏的Help—>Edit Custom VM Options &#xff0c;在打开的studio64.exe.vmoptions文件后面添加&#xff1a;(要注意不能有空格&#xff0c;否则st…...

java生成随机数

代码 startValue 开始值 endValue 结束值 per生成的位数也就是精度 /*** 随机数的生成* param startValue* param endValue* return*/private BigDecimal randomBigDecimal(String startValue, String endValue,int per) {BigDecimal min new BigDecimal(startValue);BigDeci…...

动态定制深度学习:Mojo模型与自定义训练算法的无缝切换

动态定制深度学习&#xff1a;Mojo模型与自定义训练算法的无缝切换 引言 在机器学习领域&#xff0c;算法的选择对模型的性能有着决定性的影响。随着研究的深入和技术的发展&#xff0c;开发者可能需要根据不同的数据特性和业务需求&#xff0c;动态地切换或自定义训练算法。…...

昇思25天学习打卡营第19天|DCGAN生成漫画头像

DCGAN生成漫画头像总结 实验概述 本实验旨在利用深度卷积生成对抗网络&#xff08;DCGAN&#xff09;生成动漫头像&#xff0c;通过设置网络、优化器以及损失函数&#xff0c;使用MindSpore进行实现。 实验目的 学习和掌握DCGAN的基本原理和应用。熟悉使用MindSpore进行图像…...

排序题目:按照频率将数组升序排序

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;按照频率将数组升序排序 出处&#xff1a;1636. 按照频率将数组升序排序 难度 3 级 题目描述 要求 给定一个整数数组 nums \texttt{nums} nums&a…...

实分析与测度论问题的分类

实分析主要研究实数、实数序列、实数极限以及实值函数的分析&#xff0c;而度量空间则是一个具有距离函数的集合&#xff0c;其分类可以从多个角度进行。 实分析 实分析主要关注实数、实数序列、实数极限以及实值函数的分析。它涉及到多个重要的概念和理论&#xff0c;包括但…...

动态代理更改Java方法的返回参数(可用于优化feign调用后R对象的统一处理)

动态代理更改Java方法的返回参数&#xff08;可用于优化feign调用后R对象的统一处理&#xff09; 需求原始解决方案优化后方案1.首先创建AfterInterface.java2.创建InvocationHandler处理代理方法3. 调用 实际运行场景拓展 需求 某些场景&#xff0c;调用别人的方法&#xff0…...

Redis缓存数据库进阶——Redis与分布式锁(6)

分布式锁简介 1. 什么是分布式锁 分布式锁是一种在分布式系统环境下&#xff0c;通过多个节点对共享资源进行访问控制的一种同步机制。它的主要目的是防止多个节点同时操作同一份数据&#xff0c;从而避免数据的不一致性。 线程锁&#xff1a; 也被称为互斥锁&#xff08;Mu…...

网络芯片(又称为PHY网络芯片)

Realtek RTL8152B是一种常见的主板集成网络芯片&#xff08;又称为PHY网络芯片&#xff09;。PHY芯片是指将网络控制芯片的运算部分交由处理器或南桥芯片处理&#xff0c;以简化线路设计&#xff0c;从而降低成本。 https://www.realtek.com/Download/List?cate_id585 Realt…...

01 Go Web基础_20240728 课程笔记

概述 如果您没有Golang的基础&#xff0c;应该学习如下前置课程。 基础不好的同学每节课的代码最好配合视频进行阅读和学习&#xff0c;如果基础比较扎实&#xff0c;则阅读本教程巩固一下相关知识点即可&#xff0c;遇到不会的知识点再看视频。 视频课程 最近发现越来越多…...

嵌入式学习Day12---C语言提升

目录 一、指针数组 1.1.什么是指针数组 2.2. 格式 2.3.存储 2.4.与字符型二维数组相比 2.5.什么时候使用指针数组 2.6.练习 二、数组指针 2.1.什么是数组指针 2.2.格式 2.3.一维数组 2.3.特点 2.4.什么时候使用 三、指针和数组的关系 3.1.一维数组和指针 …...

6.6 使用dashboard商城搜索导入模板

本节重点介绍 : 模板商城中搜索模板导入模板修改模板 大盘模板商城地址 免费的 地址 https://grafana.com/grafana/dashboards 搜索模板技巧 详情 导入dashboard 两种导入模式 url导入id导入json文件导入 导入 node_exporter模板 https://grafana.com/grafana/dashboa…...

一文讲透useMemo和useCallback

在React项目中是经常会使用到useMemo&#xff0c;useCallBack的&#xff0c;这是两个优化性能的方法&#xff0c;那么useMemo&#xff0c;useCallBack到底是什么呢&#xff1f;什么时候用呢&#xff1f; 下面将给打击分享相关知识&#xff0c;希望对大家有所帮助同时欢迎讨论指…...

【环境变量】安装了一个软件,如何配置环境变量?

配置环境变量为啥&#xff1f; 方便地在任何文件夹下调用某一指定目录下的文件。 配置步骤 以jdk17为例。 1.打开环境变量配置页面 2.新建一个变量&#xff0c;变量名为JAVA_HOME&#xff0c;内容为jdk的path路径 3.打开path变量&#xff0c;新建一个%JAVA_HOME%\bin&#x…...

重生之我当程序猿外包

第一章 个人介绍与收入历程 我出生于1999年&#xff0c;在大四下学期进入了一家互联网公司实习。当时的实习工资是3500元&#xff0c;公司还提供住宿。作为一名实习生&#xff0c;这个工资足够支付生活开销&#xff0c;每个月还能给父母转1000元&#xff0c;自己留2500元用来吃…...

我想给 git 分支换一个名字,应该怎么做?

Git中重命名分支的操作步骤如下: 确保你在要重命名的分支上。可以使用git branch或git status命令查看当前所在分支[1][2]. 使用以下命令重命名当前分支: git branch -m new-branch-name例如,将当前分支重命名为"feature-xyz": git branch -m feature-xyz-m参数是&q…...

echarts多stack的legend点选

echarts支持点击legend&#xff0c;实现显示和隐藏legend对应的数据&#xff0c;具体就是option里series里,name为legend值的数据。 如果配置了多个stack&#xff0c;那么可能你可能设置了多组legend&#xff0c;你点选的是多个legend组中的某组中的一个&#xff0c;那么如果不…...

搭建自己的金融数据源和量化分析平台(四):自动化更新上市公司所属一级、二级行业以及股票上市状态

前面做了更新沪深交易所的上市股票列表的读取和更新&#xff0c;但一旦股票退市则需要在数据库里将该股票状态更新为退市&#xff0c;同时附上退市日期&#xff0c;将股票名更改为XX退。 此外深交所下载的xls解析出来是没有上市公司所属的二级行业的&#xff0c;因此还需要建立…...

科创板重启IPO上会!募投审核新方向?思看科技等优化募投项目

撰稿 | 多客 来源 | 贝多财经 根据上交所项目审核动态最新公告&#xff0c;思看科技&#xff08;杭州&#xff09;股份有限公司&#xff08;简称“思看科技”&#xff09;将于8月2日上会&#xff0c;标志着时隔50天后科创板重新迎来首家上会企业&#xff0c;也标志着思看科技…...

深入解析损失函数:从基础概念到YOLOv8的应用

深入解析损失函数&#xff1a;从基础概念到YOLOv8的应用 在机器学习和深度学习中&#xff0c;损失函数是至关重要的组件&#xff0c;它们衡量模型的预测值与真实值之间的差距&#xff0c;从而指导模型的优化过程。本文将详细探讨损失函数的基本概念&#xff0c;及其在YOLOv8中…...

2.11.ResNet

ResNet 动机&#xff1a;我们总是想加更多层&#xff0c;但加更多层并不总是能改进精度 可以看出F1到F6模型越来越大&#xff0c;但F6距离最优解却总变远了&#xff0c;反而效果不好&#xff0c;通俗的来说就是学偏了&#xff0c;实际上我们希望是这样的&#xff1a; ​ 更大…...

GitLab添加TortoiseGIT生成SSH Key

文章目录 前言一、PuTTYgen二、GitLab 前言 GitLab是一个用于托管代码仓库和项目管理的Web平台&#xff0c;公司搭建自己的gitlab来管理代码&#xff0c;我们在clone代码的时候可以选择http协议&#xff0c;也可以选择ssh协议来拉取代码。 SSH (Secure Shell)是一种通过网络进…...

20240729 大模型评测

参考&#xff1a; MMBench&#xff1a;基于ChatGPT的全方位多模能力评测体系_哔哩哔哩_bilibili https://en.wikipedia.org/wiki/Levenshtein_distance cider: https://zhuanlan.zhihu.com/p/698643372 GitHub - open-compass/opencompass: OpenCompass is an LLM evalua…...

基于微信小程序的校园警务系统/校园安全管理系统/校园出入管理系统

摘要 伴随着社会以及科学技术的发展&#xff0c;小程序已经渗透在人们的身边&#xff0c;小程序慢慢的变成了人们的生活必不可少的一部分&#xff0c;紧接着网络飞速的发展&#xff0c;小程序这一名词已不陌生&#xff0c;越来越多的学校机构等都会定制一款属于自己个性化的小程…...

达梦数据库归档介绍

一、什么是归档 数据库归档是一种数据管理策略&#xff0c;它涉及将旧的、不经常访问的数据移动到一个单独的存储设备&#xff0c;以便在需要时可以检索&#xff0c;同时保持数据库的性能和效率。 归档的主要目标是为了释放数据库中的空间&#xff0c;以便更有效地利用高性能…...

OpenAI推出AI搜索引擎SearchGPT

OpenAI推出AI搜索引擎SearchGPT 据英国《卫报》和美国消费者新闻与商业频道等媒体报道&#xff0c;7月25日&#xff0c;OpenAI宣布正在测试一款名为SearchGPT的全新人工智能&#xff08;AI&#xff09;搜索工具。该工具能够实时访问互联网信息&#xff0c;旨在为用户提供更具时…...

elementplus菜单组件的那些事

在使用 elementplus 的菜单组件时&#xff0c;我发现有很多东西是官方没有提到但是需要注意的点 1. 菜单组件右侧会有一个边框 设置css .el-menu {border: 0 !important; } 2. 使用其他的 icon 文字内容一定要写在 这个 名字为 title 的插槽中 <el-menu-itemv-for"it…...

【VSCode实战】Golang无法跳转问题竟是如此简单

上一讲【VSCode实战】Go插件依赖无法安装 – 经云的清净小站 (skycreator.top)&#xff0c;开头说到了在VSCode中Golang无法跳转的问题&#xff0c;但文章的最后也没给出解决方案&#xff0c;只解决了安装Go插件的依赖问题。 解决了插件依赖问题&#xff0c;无法跳转的问题也离…...

three.js中加载ply格式的文件,并使用tween.js插件按照json姿态文件运动

先贴一下文件地址&#xff1a; aa.ply 文件&#xff1a; https://download.csdn.net/download/yinge0508/89595650?spm1001.2014.3001.5501 new.json https://download.csdn.net/download/yinge0508/89595641?spm1001.2014.3001.5501 代码: <template><div>&…...

性能对比:Memcached 与 Redis 的关键差异

性能对比&#xff1a;Memcached 与 Redis 的关键差异 在选择合适的缓存系统时&#xff0c;Memcached 和 Redis 是最常被提及的两种技术。它们都是内存存储系统&#xff0c;用于提高数据访问速度和应用性能。尽管它们在功能上有很多相似之处&#xff0c;但在性能、特性和应用场…...

app-routing.module.ts 简单介绍

Angular的路由是一种功能&#xff0c;它允许应用程序响应不同的URL路径或参数并根据这些路径加载不同的组件。app-routing.module.ts是Angular项目中负责设置应用程序路由的文件。 以下是一个简单的app-routing.module.ts文件示例&#xff0c;它配置了三个路由&#xff1a; i…...

基于JSP的水果销售管理网站

你好&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a; Java 数据库&#xff1a; MySQL 技术&#xff1a; JSP技术 工具&#xff1a; 未在文档中明确指出&#xff0c;可能包括但不限于IDEs&#xff08;如Ec…...

web3d值得学习并长期发展,性价比高吗?

在数字化浪潮日益汹涌的今天&#xff0c;Web3D技术以其独特的魅力和广泛的应用前景&#xff0c;逐渐成为技术领域的焦点。对于许多热衷于技术探索和创新的人来说&#xff0c;学习并长期发展Web3D技术无疑是一个值得考虑的选择。那么&#xff0c;Web3D技术的学习和发展究竟是否性…...

【大数据面试题】38 说说 Hive 怎么行转列

一步一个脚印&#xff0c;一天一道大数据面试题 博主希望能够得到大家的点赞收藏支持&#xff01;非常感谢 点赞&#xff0c;收藏是情分&#xff0c;不点是本分。祝你身体健康&#xff0c;事事顺心&#xff01; 行转列 假设我们有一张名为 sales_data 的表&#xff0c;其中包含…...