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

vue选项式写法项目案例(购物车)

一、初始化项目结构

1.初始化vite项目

npm create vite
cd vite-project
npm install

2.清理项目结构

清空App.vue

删除components目录下的HelloWorld.vue组件

3.为组件的样式启用sacc或less组件

npm i sass

4.初始化index.css全局样式

:root{
  font-size:12px
}

二、封装es-header组件

1.允许用户自定义title标题内容

2.允许用户自定义color文字颜色

3.允许用户自定义bgcolor背景颜色

4.允许用户自定义fsize字体大小

5.组件必须固定到页面顶部位置,高度45px,文字居中,z-index为999

<template>
    <div class="head-container" :style="{backgroundColor:bgcolor,color:color,fontSize:fsize+'px'}">{{ title }}</div>
</template>
<script>
import bus from '../../ulits/eventBus'
export default {
    props:{
        title:{
            type:String,
            default:'es-header'
        },
        bgcolor:{
            type:String,
            default:'#007bff'
        },
        color:{
            type:String,
            default:'#fff'
        },
        fsize:{
            type:Number,
            default:'12'
        },
    }
}
</script>
<style scoped lang="scss">
.head-container{
    position: fixed;
    top:0;
    left: 0;
    width: 100%;
    height: 45px;
    text-align: center;
    line-height: 45px;
    z-index:999;
}
</style>

三、基于axios请求商品列表数据

1.安装axios

npm i axios -S

2.在main.js入口文件中导入并配置axios

import axios from 'axios'
//配置请求的根路径
axios.defaults.baseURL='http://localhost:3000'
//将axios挂载为全局的$http自定义属性
app.config.globalProperties.$http=axios

// 从vue中按需导入createApp函数,用于创建vue的实例对象
import { createApp } from 'vue'
// 导入待渲染的App组件
import App from './App.vue'
import './style.css'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import router from "./routers/index.js";
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import axios from 'axios'
// 创建vue的实例对象
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
  }
axios.defaults.baseURL='http://localhost:3000'
app.config.globalProperties.$http=axios
app.use(ElementPlus)
app.use(router)
// 指定vue控制的Dom区域,把App组件的模板结构渲染到指定的el区域中
app.mount('#app')

3.请求商品列表数据

四、封装es-footer组件

1.组件必须固定到页面底部位置,高度50px,内容两端贴边对其,z-index为999

2.允许用户自定义amount总价格,渲染时保留两位小数

3.允许用户自定义totalt总数量,并渲染到结算按钮中,如果要结算的商品数量为0,则禁用结算按钮

4.允许用户自定义isfull全选按钮的选中状态

5.允许用户通过自定义事件的形式,监听全选按钮选中状态的变化,并获取到最新的选中状态

<template>
  <div class="footer-container">
    <div>
        <input type="checkbox" id="custom-control-label" :checked="isfull" @change="onCheckboxChange" /><label for="custom-control-label">全选</label>
    </div>
    <div>
        <span>合计:</span>
        <span class="amount">¥{{ amount.toFixed(2)}}</span>
    </div>
    <el-button class="btn-settle" :disabled="total===0">结算({{total}})</el-button>
  </div>
</template>
<script>
export default {
    props:{
        amount:{
            type:Number,
            dafault:0
        },
        total:{
            type:Number,
            dafault:0
        },
        isfull:{
            type:Boolean,
            default: false
        }
    },
    emits:['fullChange'],
    methods:{
        onCheckboxChange(e){
            this.$emit('fullChange',e.target.checked)
        }
    }
}
</script>

<style scoped lang="scss">
.footer-container{
    width: 100%;
    height: 50px;
    border-top:1px solid #ededed;
    background-color: #fff;
    position: fixed;
    bottom:0;
    left:0;
    padding:0 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    input{
       vertical-align: middle; 
    }
    .amount{
        color:red;
    }
    .btn-settle{
        min-width: 100px;
        height: 38px;
        border-radius: 19px;
    }
}
</style>

五、封装es-goods组件

1.实现edgoods组件的基本布局

2.封装组建的6的自定义属性id,thumb,title,price,count,checked

3.封装组件的自定义事件stateChange,允许外界 监听组件选中状态的变化

<template>
  <div class="goods-container">
    <div class="left">
        <input type="checkbox" :id="id" :checked="checked" @change="onCheckboxChange" />
        <label :for="id"><img :src="thumb" alt=""></label>
    </div>
    <div class="right">
        <div class="top">{{ title }}</div>
        <div class="bottom">
            <div class="price">¥{{ price.toFixed(2) }}</div>
            <EsCounter :count="count" :min="1" @numberChange="numberChange"></EsCounter>
        </div>
    </div>
  </div>
</template>
<script>
import EsCounter from './esCounter.vue'
export default {
    components:{
        EsCounter
    },
    props:{
        id:{
            type:String,
            default:'',
            require:true
        },
        thumb:{
            type:String,
            default:'',
            require:true
        },
        title:{
            type:String,
            default:'',
            require:true
        },
        price:{
            type:Number,
            default:0,
            require:true
        },
        count:{
            type:Number,
            default:0,
            require:true
        },
        checked:{
            type:Boolean,
            default:false,
            require:true
        }
    },
    emits:['stateChange','countChange'],
    methods:{
        onCheckboxChange(e){
            this.$emit('stateChange',e.target.id,e.target.checked)
        },
        numberChange(num){
            this.$emit('countChange',this.id,num)
        }
    }
}
</script>

<style scoped lang="scss">
.goods-container{
    width: 100%;
    padding:10px;
    display: flex;
    border:1px solid #ededed;
    .left{
        width: 110px;
        height: 100px;
        display: flex;
        justify-content: space-between;
        align-items: center;
        img{
            width: 100px;
            height: 100px;
        }
        input{
           vertical-align: middle; 
        }
    }
    .right{
        padding: 10px;
        flex:1;
        display: flex;
        flex-direction: column;
        justify-content: space-around;
        .bottom{
            display: flex;
            justify-content: space-between;
            align-items: center;
            .price{
                color:red;
            }
        }
    }
}
</style>

六、实现合计、结算数量、全选功能

<template>
    <div class="son">
      <EsHeader title="案例"></EsHeader>  
      <EsGoods v-for="goods in goodsList" :key="goods.id" :id="goods.id" :thumb="goods.thumb" :title="goods.title" :price="goods.price" :count="goods.count" :checked="goods.state" @stateChange="stateChange" @countChange='countChange'></EsGoods>
      <EsFooter :isfull="isfull" :amount="amount" :total="total" @fullChange="fullChange"></EsFooter>
    </div>
</template>
<script>
import EsHeader from './EsHeader.vue'
import EsFooter from './esFooter.vue'
import EsGoods from './EsGoods.vue'
export default {
    components:{EsHeader,EsGoods,EsFooter},
    data(){
        return{
            goodsList:[],
            amount:0,
            total:0
        }
    },
    methods:{
        async getGoodsList(){
           const {data:res}= await this.$http.get('/goodsList')
           this.goodsList = res
        },
        fullChange(flag){
            this.goodsList.forEach(item=>item.state =flag)
        },
        stateChange(id,checked){
            const findRes = this.goodsList.find((item)=>{
                return item.id==id;
            })
            if(findRes){
                findRes.state =checked;
            }
            this.isfull = this.goodsList.every(item=>item.state);
        },
        countChange(id,count){
            const findRes = this.goodsList.find((item)=>{
                return item.id==id;
            })
            if(findRes){
                findRes.count =count;
            }
        }
    },
    created(){
        this.getGoodsList()
    },
    computed:{
        total(){
            let a=0;
            this.goodsList.filter(item=>item.state).forEach(item=>a+=item.count)
            return a
        },
        amount(){
            let sum=0;
            this.goodsList.filter(item=>item.state).forEach(item=>sum+=item.count*item.price)
            return sum
        },
    }
}
</script>
  
<style scoped lang="scss">
.son{
    padding: 45px 0 50px 0;
}
</style>

七、封装es-counter组件能

1.渲染组件的基础布局

2.实现数量值得加减操作

3.处理min值

4.使用watc处理文本框输入的结果

5.封装numChange自定义事件

<template>
  <div class="counter-contain">
    <button class="btn" :disabled="num===1" @click="onSubClick"> -</button>
    <input type="number" class="counter-input" v-model.number.lazy="num" >
    <button class="btn"  @click="onAddClick">+</button>
  </div>
</template>
<script>
export default {
    props:{
        count:{
            type:Number,
            default:0,
            require:true
        },
        min:{
            type:Number,
            default:0,
            require:NaN
        }
    },
    emits:['numberChange'],
    data(){
        return{
           num: this.count
        }
    },
    methods:{
        onSubClick(){
            if(isNaN(this.min)&& this.num-1<this.min)return;
            this.num--
        },
        onAddClick(){
            this.num++
        },
    },
    watch:{
        num:{
            handler(newVal,oldVal){
                const parseRes = parseInt(newVal);
                //不是数字或者小于1,强制等于1
                if(isNaN(parseRes) ||parseRes<1){
                    this.num=1
                    return
                }
                // //如果新值是小数,把转换的结果赋给num
                if(String(parseRes).includes('.')==-1){
                    this.num=parseRes
                    return
                }
                this.$emit('numberChange',this.num)
            }
        }
    }
}
</script>
<style scoped lang="scss">
.counter-contain{
 .btn{
    width: 34px;
}
.counter-input{
    width: 36px;
}   
}

</style>


http://www.kler.cn/news/311706.html

相关文章:

  • 制作网上3D展馆需要什么技术并投入多少费用?
  • JSP分页功能实现案例:从基础到应用的全面解析
  • python SQLAlchemy 数据库连接池
  • 《拿下奇怪的前端报错》序章:报错输出个数值数组Buffer(475) [Uint8Array],我来教它说人话!
  • 【Unity】检测鼠标点击位置是否有2D对象
  • Modbus_tcp
  • 数据结构-3.2.栈的顺序存储实现
  • 3.数据类型
  • 算法打卡 Day41(动态规划)-理论基础 + 斐波那契数 + 爬楼梯 + 使用最小花费爬楼梯
  • python脚本转mac app+app签名公正
  • 开源 AI 智能名片 S2B2C 商城小程序与正能量融入对社群归属感的影响
  • python 实现armstrong numbers阿姆斯壮数算法
  • 利用pandas为海量数据添加UUID并实现精准筛选
  • 开放标准如何破解企业数字化与可持续发展的困境:The Open Group引领生态系统架构创新
  • 新电脑工作流搭建记录-前端篇
  • 《ElementUI/Plus 基础知识》el-table + sortablejs 实现 row 拖动改变顺序(Vue2/3适用)
  • C++对C的扩充
  • 二百六十六、Hive——Hive的DWD层数据清洗、清洗记录、数据修复、数据补全
  • ros跨平台订阅和发布消息(ip如何设置)
  • Springboot的三层架构
  • ⭐ Unity + OpenCV 实现实时图像识别与叠加效果
  • HTML基础和常用标签
  • 【C++笔记】八、结构体 [ 3 ]
  • 如何着手创建企业数据目录?(一)数据目录的设定
  • python 实现area under curve曲线下面积算法
  • libserailport交叉编译适配说明
  • 胤娲科技:解锁AI奥秘——产品经理的智能进化之旅
  • 【每天学点AI】一个例子带你了解Python装饰器到底在干嘛!
  • C语言中的一些小知识(二)
  • Android 恢复挑战和解决方案:如何从 Android 设备恢复删除的文件