vue+vue-router+vuex地址管理思路

1、场景描述

如何精简页面目录,在实现功能要求的同时,提升页面可维护性成为前端发展趋势。收货地址管理是电商交易必不可少模块,本篇我将经过实现地址管理的部分功能分享下构建思路。
前端

本篇会涉及到:es六、vuejs、vue-router、vuex基础知识,在讲解思路过程当中,我会穿插说明,可是仍是但愿读者对相关知识有些了解。
vue

实现功能:

一、我的中心与订单确认页都可以进入地址列表页;
es6

二、我的中心进入地址列表页,点击地址列表中地址进入地址编辑页,并带出地址相关信息;
vue-router

三、订单确认页进入地址列页,点击地址列表中地址,选中地址并返回到订单确认页,并带出选中地址信息;
vuex

2、实现功能图解


3、解决该问题思路及代码

注:该篇思路分析项目Demo是使用vue-cli 3.x版本搭建。
vue-cli

一、Demo目录

  1. 在组件库中建立了appHeader.vue,用于头部的名称展现。
  2. “页面”库中新建了四个“页面”Home.vue(我的中心)、OrderConfirm.vue(订单确认)、AddressList.vue(地址列表)、AddressEdit.vue(地址编辑)。项目初始化时的“页面”About.vue删除。
  3. App.vue中路由连接改造,会在后边页面介绍中说明。
  4. 路由文件:Demo建立中,路由数量有限,且主要目的在功能实现,所以本次路由信息均放在了router.js文件中。
  5. 状态管理器:同路由文件相似,咱们将状态、方法均放在store.js文件中。


二、路由匹配

在router.js文件中匹配好全部的路由信息,将本次Demo演示的四个页面的路由信息均匹配好。bash

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import OrderConfirm from './views/OrderConfirm.vue'
import AddressList from './views/AddressList.vue'
import AddressEdit from './views/AddressEdit.vue'

Vue.use(Router)

export default new Router({
    routes: [{
            path: '/',
            name: 'home',
            component: Home
        },
        {
            path: '/orderConfirm',
            name: 'orderConfirm',
            component: OrderConfirm
        },
        {
            path: '/addressList',
            name: 'addressList',
            component: AddressList
        },
        {
            path: '/addressEdit',
            name: 'addressEdit',
            component: AddressEdit
        }
    ]
})复制代码

三、“页面”建立及对应路由与状态管理说明

App.vue:初始化时的页面,系统入口。此处作了点修改:template内容中路由连接信息。app

<template>
    <div id="app">
        <div id="nav">
            <router-link to="/">Home</router-link> ||
            <router-link to="/orderConfirm">OrderConfirm</router-link>
        </div>
        <router-view />
    </div>
</template>复制代码

Home.vue:我的中心页,做为编辑地址列表的入口。函数

<template>
    <div class="home">
        <router-link to='/addressList'>管理地址</router-link>
    </div>
</template>
<style scoped>
a {
    text-decoration: none;
    color: black;
}
</style>复制代码
说明:
  • Home页面在本次项目Demo就是一个连接跳转的路径,仅仅使用了咱们在router.js中设置的地址列表路由/addressList
store.js:状态管理文件,为方便下边“页面”说明,提早将文件内容贴出来,后续涉及到时会进行简要说明。
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        addressList: [{
                id: 1,
                username: "小明",
                phone: '15612345678',
                addressDetail: "某某省 某某市 某某区 110"
            },
            {
                id: 2,
                username: "小红",
                phone: '13812345678',
                addressDetail: "某某省 某某市 某某区 110"
            },
            {
                id: 3,
                username: "小花",
                phone: '18612345678',
                addressDetail: "某某省 某某市 某某区 110"
            }
        ]
    },
    getters: {
        getAddress: (state, getters) => (id) => {
            return state.addressList.find(address => address.id === id)
        }
    },
    mutations: {
        addAddress(state, address) {
            return state.addressList.push(address)
        }
    }
})复制代码

OrderConfirm.vue:订单确认页,是选择收货地址入口,正是因为存在跟Home两个入口,AddressList.vue中地址列表对于地址进行同一个操做,存在不一样的反馈。优化

<template>
    <div>
        <router-link to='/addressList'>
            <div v-if='isAddress' class="address">
                <div><span>姓名:{{username}}</span></div>
                <div><span>电话:{{phone}}</span></div>
                <div><span>地址:{{addressDetail}}</span></div>
            </div>
            <div v-else>
                <span>选择地址</span>
            </div>
        </router-link>
    </div>
</template>
<script>
export default {
    name: "orderConfirm",
    data() {
        return {
            isAddress: false,
            username: "",
            phone: "",
            addressDetail: ""
        }
    },
    created() {
        if (this.$route.query.id) {
            let userAddress = this.$store.getters.getAddress(this.$route.query.id)
            this.isAddress = true
            this.username = userAddress.username;
            this.phone = userAddress.phone;
            this.addressDetail = userAddress.addressDetail;
        }
    }
}
</script>
<style>
a {
    text-decoration: none;
    color: black;
}

.address {
    text-align: left;
    margin-left: 20PX;
}
</style>复制代码

说明:

  • 使用isAddress确认是否有地址,默认为false。当地址不存在时,显示为“选择地址”,当地址存在时,或者选择地址后,显示选中地址信息。
  • this.$route.query.id是vue-router中query参数,该使用是组件中获取参数query.id方式,经过这个字段值去判断是否存在地址信息。若是存在显示地址信息,并设置isAddresstrue,若是不存在则显示为选择地址。
  • getters是vuex中计算属性,相似于vue中的computed,咱们能够经过getters获取vuex通过“计算”的数据。
  • 视角转向store.js文件,getters中使用es6的箭头函数,经过输入值,获取state中通过“计算”的数据。
  • this.$store.getters.getAddress(this.$route.query.id)是为获取vuex中传参的getters数据。在返回选中地址时,经过向getters传递this.$route.query.id获取选中的数据,将返回结果赋值到初始设置字段便可。
AddressList.vue:地址列表页。该页面须要经过判别路由后初始化页面。
<template>
    <div>
        <app-header headTitle="地址列表"></app-header>
        <ul>
            <li v-for="address in addressList" :key="address.id">
                <router-link :id='address.id' :to="{path:url,query:{id:address.id}}">
                    <div>
                        <div>
                            <span>姓名:{{address.username}}</span>
                        </div>
                        <div>
                            <span>电话:{{address.phone}}</span>
                        </div>
                        <div>
                            <span>地址:{{address.addressDetail}}</span>
                        </div>
                    </div>
                </router-link>
            </li>
        </ul>
        <div>
            <router-link to='/addressEdit'><button>新增地址</button></router-link>
        </div>
    </div>
</template>
<script>
import appHeader from '@/components/appHeader.vue'
import { mapState } from 'vuex'
export default {
    name: "addressList",
    components: {
        appHeader: appHeader,
    },
    data() {
        return {
            url: ""
        }
    },
    computed: {
        ...mapState(["addressList"])
    },
    beforeRouteEnter(to, from, next) {
        if (from.name == 'orderConfirm') {
            next(vm => {
                vm.url = "/orderConfirm"
            })
        } else {
            next(vm => {
                vm.url = "/addressEdit"
            })
        }

    }
}
</script>
<style scoped>
ul li {
    list-style: none;
    text-align: left;
    margin-bottom: 10px;
    padding: 20px;
}

ul li:nth-child(even) {
    background-color: lightgrey;
}

a {
    text-decoration: none;
    color: black;
}

button {
    outline: none;
    border: none;
    width: 100px;
    height: 40px;
    border-radius: 10px;
    background-color: green;
    color: white;
}
</style>复制代码
说明:
  • 页面初始化时,地址列表经过vuex辅助函数mapState获取state中地址列表数据,并经过v-for指令进行列表渲染。
  • 该页面进行初始渲染的关键是获取路由导航来源,经过组件内路由导航守卫beforeRouteEnter实现,由于没法获取组件实例this,所以在next方法中进行实例获取。
  • 动态绑定url,可根据路由导航来源决定导航跳转去向,另外在url中动态绑定query参数。
  • 在跳转过程当中,带着query.id参数,即在本次Demo中不少‘页面’中均存在this.$route.query.id验证。
  • 另外,本页中使用了组件app-header,对于页面头进行简单设计。
  • 最后,在页面底部添加了一个新增地址按钮,是为在演示如何在一个页面实现新增与修改地址功能。
appHeader.vue:头部样式组件,用在了地址列表页面和地址编辑页面。
<template>
    <div class='header'>
        <span>{{headTitle}}</span>
    </div>
</template>
<script>
export default {
    name: "appHeader",
    props: ['headTitle'],
}
</script>
<style>
.header {
    width: 100%;
    height: 60px;
    text-align: center;
    color: white;
    background-color: lightblue;
    font-size: 20px;
    line-height: 60px;
}
</style>复制代码

说明:

  • 这个组件没有太多难点,仅仅涉及到props的使用。
AddressEdit.vue:地址编辑页面。
<template>
    <div>
        <appHeader :headTitle="addressEdit"></appHeader>
        <div class='name'>
            <span>姓名:</span><input type="text" v-model='username'>
        </div>
        <div class='phone'>
            <span>电话:</span><input type="text" v-model='phone'>
        </div>
        <div class='addressDetail'>
            <span>地址:</span><input type="text" v-model='addressDetail'>
        </div>
        <router-link to='/addressList'><button @click='editAddress'>提交</button></router-link>
    </div>
</template>
<script>
import appHeader from '@/components/appHeader.vue'
import { mapGetters } from 'vuex'
export default {
    name: "addressEdit",
    data() {
        return {
            addressEdit: "",
            username: '',
            phone: '',
            addressDetail: ''
        }
    },
    components: {
        appHeader: appHeader
    },
    computed: {
        useraddress() {
            return this.$store.getters.getAddress(this.$route.query.id)
        }
    },
    methods: {
        editAddress() {
            let length = this.$store.state.addressList.length
            let address = {}
            address.id = length + 1
            address.username = this.username
            address.phone = this.phone
            address.addressDetail = this.addressDetail
            this.$store.commit("addAddress", address)
        }
    },
    created() {
        this.$route.query.id ? this.addressEdit = '编辑地址' : this.addressEdit = '新增地址';
        if (this.$route.query.id) {
            let userAddress = this.$store.getters.getAddress(this.$route.query.id)
            this.username = userAddress.username || '';
            this.phone = userAddress.phone || '';
            this.addressDetail = userAddress.addressDetail || '';
        }

    }

}
</script>
<style>
input {
    border: 1px solid lightblue;
    outline: none;
    width: 300px;
    height: 30px;
    border-radius: 5px;
}

.name {
    margin-top: 10px;
}

.phone {
    margin: 10px 0;
}

button {
    margin-top: 20px;
    outline: none;
    border: none;
    width: 100px;
    height: 40px;
    border-radius: 10px;
    background-color: green;
    color: white;
}
</style>复制代码

说明:

  • 头部组件app-headerprops动态赋值,点击新增地址按钮,进入地址编辑页,页面头部展现“新增地址”,点击地址列表中地址,进入地址编辑页,页面头部展现为“编辑地址”。
  • 地址修改时,对于输入框内容根据this.$route.query.id从vuex中getters赋值并展现。
  • mutations方法相似vue中methods
  • 信息填写完毕后,经过mutations方法向vuex中state中值进行修改。在组件中methods中经过this.$store.commit("addAddress", address)提交到mutations。
  • 注意在本次的Demo展现中,我针对地址修改与新增,均向state中地址列表中新增地址,另外,咱们不一样入口进行地址列表页面时,新增地址提交返回路径地址也应该不同,有兴趣的同窗们能够尝试修改的方法。鉴因而个本地展现,本次展现数据修使用的mutations,真正与后台交互中,建议使用actions.

4、写在后面

实际咱们在作产品时,涉及到用户体验的东西不少,好比页面样式、默认地址、输入验证、验证提示、地址级联选择等等,做为一个功能实现,暂不予考虑。

以上是做为一名喜欢前端技术的产品经理实现该功能的思路及方法,相信大神们会有更简洁便利的方式。

最后,针对文中有不对的地方,或者能够再优化的点,请多多指教。

相关文章
相关标签/搜索