Vue3前端开发pinia实战——出版社图书销售统计

        Pinia是一个轻量级状态管理库,运行跨组件或页面共享状态,解决了多组件之间的数据通信,使得数据操作更加简洁。

        pinia只有state、getters和actions,分模块是不需要借助modules,使得代码编写更加容易和更加简洁。

        该“出版社图书销售系统”采用了Pinia进行状态管理,设计了Pinia的模块化和持久化存储。

1.设计要求

      (1)  “增加图书销售信息”按钮的主要功能是根据输人ID(如1001)查询相关出版社信息是否存在,若存在,则显示出版社的名称(如清华大学出版社),接下来继续输人其余相关信息。

        单击“增加图书销售信息”按钮,则将输入的图书信息渲染到列表中,同时在出版社press 模块中自动完成相关出版社销售总量的更新(累加)。若输人的 ID(如 1004)不存)在,则需要手动在单行文本输入框中输入出版社名称,接下来同样完成其余信息的输人。

        完成后单击“增加图书销售信息”按钮,则将输入的图书信息渲染到列表中,同时在出版社press 模中自动添加新的出版社信息和销量信息。

        (2)“统计图书总销量”按钮的主要功能是单击后自动将所有出版社图书销售量进行汇总。未单击此按钮时不显示“图书总销量”。


        (3)分别定义book.js 和press.js两个模块文件。在book.js文件中,定义addBook方法,在press.js中,定义addPress、modifyPress、changeTotalAll方法,分别完成添加出版社相关信息、修改已有出版社的销售量、统计更新所有出版社图书总销量。

        book数组的信息如下:

        press数组的信息如下:

2.pinia和持久化插件的安装

        使用npm包管理工具进行安装,然后创建vue3项目,在创建好的目录下,使用add添加pinia进该项目中。

//1.pinia安装和pinia-plugin-persist的安装
npm install pinia --save
npm install pinia-plugin-persist --save

//2.使用vite创建项目vue3-pinia-book
npm create vite@latest vue3-pina-book

//3.选择 vue框架和JaveScript

//4.切换到vue3-pinia-book项目中

//5.在项目中添加pinia  --save:表示项目运行时依赖
npm add pinia@pinia的版本 --save 
npm add pinia-plugin-persist@版本好 --save

//6.
npm install
npm run dev

3.pinia的使用

        3.1编写store模块

                创建src\stor\book.js,用来存放book数组数据,以及一些相关的数据操作。

                需要导入defineStore()函数,该函数的两个参数——第一个是状态管理容器的名称,第二个参数是一个 包含了state、getters、actions和presist的对象,state用来管理数据,getters里面的方法进行再次编译,得到新的数据,actions存放事件处理方法,presist用来进行持久化存储。

        实现持久化存储的实例代码如下:

persist : {
        enabled : true,                 //开启数据缓存
        stategies : [
            {
                key : 'book',           //当前store的id
                storage : localStorage, //存储方式
                paths :['bookMsg']      //指定要持久化bookMsg
            }
        ]
    }

        下面是book.js的代码:
        在state里面编写book数组的数据;在getters里面,定义totalBooks() ,通过数组的length属性用来获取一共有多少本书籍;在actions里面,定义addBook()方法,通过判断形参里的出版社ID和书本的名字是否和已有书籍相同,如果存在相同书本,则判断书本价格是否相同,不同则不进行销售数目的累加;如果不存在相同的书本,则创建一个新的书本对象,加到bookMsg中;presist里面对持久化数据进行相关设置。

import { defineStore } from "pinia";

export const useBookStore = defineStore('books', {
    state: () => {
        return {
            bookMsg: [
                {
                    ID: '1001',
                    name: 'Vue.js前端框架技术与实战',
                    press: '清华大学出版社',
                    price: 69.8,
                    count: 1269
                },
                {
                    ID: '1001',
                    name: 'Web前端开发技术-HTML5、CSS3、JavaScript(第三版)',
                    press: '清华大学出版社',
                    price: 59.50,
                    count: 120000
                },
                {
                    ID: '1001',
                    name: 'Web前端开发技术实验与实践-HTML5、CSS3、JavaScript(第三版)',
                    press: '清华大学出版社',
                    price: 39.50,
                    count: 43500
                },
                {
                    ID: '1002',
                    name: 'Web前端开发',
                    press: '高等教育出版社',
                    price: 35,
                    count: 23500
                },
                {
                    ID: '1002',
                    name: 'Web前端开发技术基础案例教程',
                    press: '高等教育出版社',
                    price: 48,
                    count: 12500
                }
            ]
        }
    },

    getters: {
        //计算一共有多少本书
        totalBooks() { this.bookMsg.length }

    },

    actions: {
        //添加图书销售信息
        addBook(ID, name, press, price, count) {
            let ifExit = false;

            for (let i = 0; i < this.bookMsg.length; i++) {
                //如果输入的ID和书本名都对的上,则认为这本书存在
                if (this.bookMsg[i].ID === ID && this.bookMsg[i].name === name) {

                    //判断用户输入的价格是否正确
                    if (this.bookMsg[i].price == Number(price)) {
                        ifExit = true;
                        this.bookMsg[i].count += Number(count);
                        break;
                    } else {
                        alert('书本价格输入错误,请重新输入')
                        ifExit = true
                        break
                    }


                }
            }

            //如果书本不存在,则在state中加入新书
            if (!ifExit) {
                const newBookMsg = {
                    ID: ID,
                    name: name,
                    press: press,
                    price: Number(price),
                    count: Number(count)
                };

                this.bookMsg.push(newBookMsg);
            }
        }
    },


    //持久化数据
    persist: {
        enabled: true,                 //开启数据缓存
        stategies: [
            {
                key: 'book',           //当前store的id
                storage: localStorage, //存储方式
                paths: ['bookMsg']      //指定要持久化bookMsg
            }
        ]
    }

})

        下面是press.js的代码:

        在state里编写已有的press的数据;在getters里面,定义totalPres(),通过数组的length属性,获取一共有多少个出版社,定义changeTotalAll() ,对所有出版社的书本销售数量进行相加;在actions里,定义 addPress(),在press数组里面添加新的出版社对象,定义 modifyPress(),如果出版社销售出书本,则对该出版社的销售数量total进行修改;presist里面对持久化数据进行相关设置。

import { defineStore } from "pinia";

export const usePressStore = defineStore('press', {
    state: () => {
        return {
            press: [
                {
                    ID: '1001',
                    name: '清华大学出版社',
                    total: 540000
                },
                {
                    ID: '1002',
                    name: '高等教育出版社',
                    total: 250000
                },
                {
                    ID: '1003',
                    name: '机械工业出版社',
                    total: 370000
                }
            ]

        }
    },

    getters: {
        totalPres() { this.press.length },

        //统计更新所有出版社图书总销售量
        changeTotalAll() {
            let totalAll = 0;
            for (let i = 0; i < this.press.length; i++) {
                totalAll += this.press[i].total
            }
            return totalAll
        }

    },

    actions: {
        //添加出版社相关信息
        addPress(ID, name, total) {
            const newPress = {
                ID: ID,
                name: name,
                total: Number(total)
            }

            this.press.push(newPress)
        },

        //修改已有出版社信息
        modifyPress(ID, bookCount) {
            for (let i = 0; i < this.press.length; i++) {
                if (this.press[i].ID == ID) {
                    this.press[i].total += Number(bookCount)
                    break;
                }
            }
        }
    },

    //持久化数据
    persist: {
        enabled: true,                 //开启数据缓存
        stategies: [
            {
                key: 'press',           //当前store的id
                storage: localStorage, //存储方式
                paths: ['press']      //指定要持久化press
            }
        ]
    }
})

        3.2 创建并挂载pinia示例

        使用createPinia()创建pinia对象,导入持久化数据的插件——pinia-plugin-persist,并让pinia对象使用该持久化插件。

import { createApp } from 'vue'
import './style.css'
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'
import App from './components/press-books.vue'

const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersist)

app.use(pinia)
app.mount('#app')

4.创建组件,实现相关功能和渲染内容

        在组件中导入需要用到的store模块,使用storeToRefs(),通过解构赋值,将相关的数据对象转换成响应式的,使用表格的格式进行渲染出来。

        需要有几个输入框进行出版社和书籍信息的输入,创建对应的响应式变量,通过v-bind绑定到对应的输入框中。对于出版社ID的输入框,要求在输入ID后按下回车,若该出版社已录入,会在出版社名称的输入框在渲染出来,按下回车进行相关操作,可以通过key.enter事件实现,该事件绑定了searchPressName()方法,这个方法根据输入的ID获取相关出版社名称,若不存在,则提示用户手动输入出版社名称。

        有一个“添加图书信息”的按钮,这个按钮涉及到两个store模块的数据操作,在book模块中,添加或者更新书籍销售信息,在press模块里面,添加新的出版社信息或者更新出版社的销售信息。

        在“统计图书销售量”这个按钮中,直接通过press模块里面的changeTotalAll()方法获取总销售量。

<script setup>
import { useBookStore } from '../store/book';
import { storeToRefs } from 'pinia';
import { reactive, ref } from 'vue';
import { usePressStore } from '../store/press';

const books = useBookStore()
const { bookMsg } = storeToRefs(books)

const p = usePressStore()
const { press } = storeToRefs(p)

const ID = ref('')      //出版社ID
const bookPress = ref('')   //图书出版社
const bookName = ref()    //图书名称
const bookPrice = ref()     //图书价格
const bookCount = ref()     //图书销量

//const pressName = ref('')   //出版社名称
const sameIDBooks = reactive([])  //根据用户输入的ID查找该ID的所有书本
const ifExit = ref(false)  //输入的ID的出版社是否存在
const getTotalAll = ref()      //获取press中getters中的changeTotalAll的值



//根据输入的ID获取相关出版社名称,若不存在,则提示用户手动输入出版社名称
const searchPressName = () => {
    ifExit.value = false

    for (let i = 0; i < press.value.length; i++) {
        if (press.value[i].ID === ID.value) {
            bookPress.value = press.value[i].name
            ifExit.value = true
            clean()
            break
        }

    }

    if (!ifExit.value) {
        alert('该出版社没录入,请手动输入')
        clean()
    }

}


const addPressOrModifyPress = () => {
    console.log('ifExit=', ifExit.value)
    if (ifExit.value) {
        p.modifyPress(ID.value, bookCount.value)
    }
    else {
        p.addPress(ID.value, bookPress.value, bookCount.value)
        ifExit.value = true
    }

    console.log(ifExit.value)
}

//点击按钮,进行添加书本信息和选择添加新的出版社或者更改出版社的销售书籍信息
const buttonSubmit = () => {
    books.addBook(ID.value, bookName.value, bookPress.value, bookPrice.value, bookCount.value);
    addPressOrModifyPress();
}


//清除输入框中输入的内容,
// 1.点击'清空输入内容,则只是清空图书名称、定价、销量
// 2.用户输入新的出版社id
// 3.用户输入相同的出版社id
const clean = () => {
    //如果用户再次输入的出版社id和前一次输入一样
    if (ifExit.value) {
        bookName.value = '',
            bookPrice.value = '',
            bookCount.value = ''
    } else {//用户输入新的出版社id

        bookPress.value = '',
            bookName.value = '',
            bookPrice.value = '',
            bookCount.value = ''
    }
}



</script>

<template>
    <div>
        <h1>pinia多模块实战——出版社图书销售统计</h1>
    </div>
    <hr>
    <div>
        <h2>输入图书销售明细</h2>
        <br>
        出版社ID:<input v-model="ID" placeholder="输入ID后回车" @keyup.enter="searchPressName">
        出版社名称:<input v-model="bookPress">
        <br>
        图书名称:<input v-model="bookName">
        图书定价:<input v-model="bookPrice">
        图书销量:<input v-model="bookCount">

    </div>

    <button @click="buttonSubmit">添加图书销售信息</button>
    <button @click="clean">清空输入的内容</button>

    <table border="1px">
        <caption>书本相关信息</caption>

        <thead>
            <tr>
                <th>出版社ID</th>
                <th>出版社名称</th>
                <th>书本名称</th>
                <th>书本价格</th>
                <th>已售数量</th>
            </tr>
        </thead>

        <tbody>
            <tr v-for="item in bookMsg" :key="item.ID">
                <th>{{ item.ID }}</th>
                <th>{{ item.press }}</th>
                <th>{{ item.name }}</th>
                <th>{{ item.price }}</th>
                <th>{{ item.count }}</th>
            </tr>

        </tbody>
    </table>


    <hr>
    <button @click="getTotalAll = p.changeTotalAll">统计图书总销量</button>

    <table border="1px">
        <caption>出版社相关信息</caption>
        <thead>
            <tr>
                <th>出版社ID</th>
                <th>出版社名称</th>
                <th>出版社已售数量</th>
            </tr>

        </thead>

        <tbody>
            <tr v-for="item in press" :key="item.ID">
                <th>{{ item.ID }}</th>
                <th>{{ item.name }}</th>
                <th>{{ item.total }}</th>
            </tr>
        </tbody>
    </table>


    <div v-if="getTotalAll != null">
        图书总销量:{{ getTotalAll }}
    </div>

</template>

        运行结果(编辑好样式后):


5.补充

        这个只是粗略地实现了几个添加数据的功能,还没对于输入的内容进行限制,如去掉输入的空格,限制只能输入数字等。

        对于使用alter进行提示的信息,使用Element 组件实现更好。

        这个项目是用来巩固pinia相关知识而写的,可能还存在很多不规范或者错误的地方。

参考资料:

《Vue.js 3.x 前端开发技术与实战》——储久良  清华大学出版社

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值