├── .gitignore ├── App.vue ├── README.md ├── common ├── classify.data.js ├── demo.scss ├── http.api.js ├── http.interceptor.js ├── index.list.js ├── locales │ ├── en.js │ └── zh.js └── vue-i18n.min.js ├── components └── page-nav │ └── page-nav.vue ├── main.js ├── manifest.json ├── pages.json ├── pages ├── classifications │ └── index.vue ├── index │ ├── index.vue │ └── swiper.vue ├── my │ ├── addSite.vue │ ├── address.vue │ └── index.vue └── shoppingCart │ └── index.vue ├── static ├── common │ └── js │ │ └── touch-emulator.js ├── index │ ├── ad.gif │ ├── grid_1.png │ ├── grid_10.png │ ├── grid_2.png │ ├── grid_3.png │ ├── grid_4.png │ ├── grid_5.png │ ├── grid_6.png │ ├── grid_7.png │ ├── grid_8.png │ ├── grid_9.png │ └── swiper_1.jpg ├── my │ └── header.png ├── navs │ ├── classifications.png │ ├── classifications_select.png │ ├── index.png │ ├── index_select.png │ ├── my.png │ ├── my_select.png │ ├── shoppingCart.png │ └── shoppingCart_select.png └── uview │ └── common │ ├── favicon.ico │ └── logo.png ├── store ├── $u.mixin.js └── index.js ├── uni.scss ├── uview-ui ├── LICENSE ├── README.md ├── components │ ├── u-action-sheet │ │ └── u-action-sheet.vue │ ├── u-alert-tips │ │ └── u-alert-tips.vue │ ├── u-avatar-cropper │ │ ├── u-avatar-cropper.vue │ │ └── weCropper.js │ ├── u-avatar │ │ └── u-avatar.vue │ ├── u-back-top │ │ └── u-back-top.vue │ ├── u-badge │ │ └── u-badge.vue │ ├── u-button │ │ └── u-button.vue │ ├── u-calendar │ │ └── u-calendar.vue │ ├── u-car-keyboard │ │ └── u-car-keyboard.vue │ ├── u-card │ │ └── u-card.vue │ ├── u-cell-group │ │ └── u-cell-group.vue │ ├── u-cell-item │ │ └── u-cell-item.vue │ ├── u-checkbox-group │ │ └── u-checkbox-group.vue │ ├── u-checkbox │ │ └── u-checkbox.vue │ ├── u-circle-progress │ │ └── u-circle-progress.vue │ ├── u-col │ │ └── u-col.vue │ ├── u-collapse-item │ │ └── u-collapse-item.vue │ ├── u-collapse │ │ └── u-collapse.vue │ ├── u-column-notice │ │ └── u-column-notice.vue │ ├── u-count-down │ │ └── u-count-down.vue │ ├── u-count-to │ │ └── u-count-to.vue │ ├── u-divider │ │ └── u-divider.vue │ ├── u-dropdown-item │ │ └── u-dropdown-item.vue │ ├── u-dropdown │ │ └── u-dropdown.vue │ ├── u-empty │ │ └── u-empty.vue │ ├── u-field │ │ └── u-field.vue │ ├── u-form-item │ │ └── u-form-item.vue │ ├── u-form │ │ └── u-form.vue │ ├── u-full-screen │ │ └── u-full-screen.vue │ ├── u-gap │ │ └── u-gap.vue │ ├── u-grid-item │ │ └── u-grid-item.vue │ ├── u-grid │ │ └── u-grid.vue │ ├── u-icon │ │ └── u-icon.vue │ ├── u-image │ │ └── u-image.vue │ ├── u-index-anchor │ │ └── u-index-anchor.vue │ ├── u-index-list │ │ └── u-index-list.vue │ ├── u-input │ │ └── u-input.vue │ ├── u-keyboard │ │ └── u-keyboard.vue │ ├── u-lazy-load │ │ └── u-lazy-load.vue │ ├── u-line-progress │ │ └── u-line-progress.vue │ ├── u-line │ │ └── u-line.vue │ ├── u-link │ │ └── u-link.vue │ ├── u-loading-page │ │ └── u-loading-page.vue │ ├── u-loading │ │ └── u-loading.vue │ ├── u-loadmore │ │ └── u-loadmore.vue │ ├── u-mask │ │ └── u-mask.vue │ ├── u-message-input │ │ └── u-message-input.vue │ ├── u-modal │ │ └── u-modal.vue │ ├── u-navbar │ │ └── u-navbar.vue │ ├── u-no-network │ │ └── u-no-network.vue │ ├── u-notice-bar │ │ └── u-notice-bar.vue │ ├── u-number-box │ │ └── u-number-box.vue │ ├── u-number-keyboard │ │ └── u-number-keyboard.vue │ ├── u-parse │ │ ├── libs │ │ │ ├── CssHandler.js │ │ │ ├── MpHtmlParser.js │ │ │ ├── config.js │ │ │ ├── handler.wxs │ │ │ └── trees.vue │ │ └── u-parse.vue │ ├── u-picker │ │ └── u-picker.vue │ ├── u-popup │ │ └── u-popup.vue │ ├── u-radio-group │ │ └── u-radio-group.vue │ ├── u-radio │ │ └── u-radio.vue │ ├── u-rate │ │ └── u-rate.vue │ ├── u-read-more │ │ └── u-read-more.vue │ ├── u-row-notice │ │ └── u-row-notice.vue │ ├── u-row │ │ └── u-row.vue │ ├── u-search │ │ └── u-search.vue │ ├── u-section │ │ └── u-section.vue │ ├── u-select │ │ └── u-select.vue │ ├── u-skeleton │ │ └── u-skeleton.vue │ ├── u-slider │ │ └── u-slider.vue │ ├── u-steps │ │ └── u-steps.vue │ ├── u-sticky │ │ └── u-sticky.vue │ ├── u-subsection │ │ └── u-subsection.vue │ ├── u-swipe-action │ │ └── u-swipe-action.vue │ ├── u-swiper │ │ └── u-swiper.vue │ ├── u-switch │ │ └── u-switch.vue │ ├── u-tabbar │ │ └── u-tabbar.vue │ ├── u-table │ │ └── u-table.vue │ ├── u-tabs-swiper │ │ └── u-tabs-swiper.vue │ ├── u-tabs │ │ └── u-tabs.vue │ ├── u-tag │ │ └── u-tag.vue │ ├── u-td │ │ └── u-td.vue │ ├── u-th │ │ └── u-th.vue │ ├── u-time-line-item │ │ └── u-time-line-item.vue │ ├── u-time-line │ │ └── u-time-line.vue │ ├── u-toast │ │ └── u-toast.vue │ ├── u-top-tips │ │ └── u-top-tips.vue │ ├── u-tr │ │ └── u-tr.vue │ ├── u-upload │ │ └── u-upload.vue │ ├── u-verification-code │ │ └── u-verification-code.vue │ └── u-waterfall │ │ └── u-waterfall.vue ├── iconfont.css ├── index.js ├── index.scss ├── libs │ ├── config │ │ ├── config.js │ │ └── zIndex.js │ ├── css │ │ ├── color.scss │ │ ├── common.scss │ │ ├── style.components.scss │ │ ├── style.h5.scss │ │ ├── style.mp.scss │ │ ├── style.nvue.scss │ │ └── style.vue.scss │ ├── function │ │ ├── $parent.js │ │ ├── addUnit.js │ │ ├── bem.js │ │ ├── color.js │ │ ├── colorGradient.js │ │ ├── debounce.js │ │ ├── deepClone.js │ │ ├── deepMerge.js │ │ ├── getParent.js │ │ ├── guid.js │ │ ├── md5.js │ │ ├── queryParams.js │ │ ├── random.js │ │ ├── randomArray.js │ │ ├── route.js │ │ ├── sys.js │ │ ├── test.js │ │ ├── throttle.js │ │ ├── timeFormat.js │ │ ├── timeFrom.js │ │ ├── toast.js │ │ ├── trim.js │ │ └── type2icon.js │ ├── mixin │ │ ├── mixin.js │ │ └── mpShare.js │ ├── request │ │ └── index.js │ ├── store │ │ └── index.js │ └── util │ │ ├── area.js │ │ ├── async-validator.js │ │ ├── city.js │ │ ├── emitter.js │ │ └── province.js ├── package.json └── theme.scss └── vue.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | /unpackage 2 | /*.zip 3 | -------------------------------------------------------------------------------- /App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

vue-mall-beautiful

3 |

uni插件市场首款基于 uview-ui 的绝佳的商城模板

4 |

uview的快捷让我叹为观止,uview-ui同时支持手机网页、APP,微信小程序、支付宝小程序、百度小城序、360小程序、QQ小程序、今日头条小程序

5 |
6 | 7 | [![](https://img.shields.io/github/stars/chuzhixin/vue-mall-beautiful?style=flat-square&label=Stars&logo=github) 8 | ](https://github.com/chuzhixin/vue-mall-beautiful) 9 | ## 郑重承诺 10 | 如果vue-mall-beautiful最终商业化成功,vmb愿意贡献每单20%的净利润用于支持uview的开发,第一次使用uview写开源项目,时间仓促欢迎体验star 11 | 12 | ## 演示地址 13 | 14 | ### - [🚀vue-mall-beautiful开源地址](https://github.com/chuzhixin/vue-mall-beautiful/) 15 | ### - 🚀vue-mall-beautiful手机端演示地址,扫码可访问(小程序、app版本需要自行下载编译) 16 | ### ![](https://gitee.com/chu1204505056/byui-bookmarks/raw/gh-pages/vmb.png) 17 | ### - [🚀vue-admin-beautiful-pro演示地址](https://chu1204505056.gitee.io/vue-admin-beautiful/?hmsr=%E6%8F%92%E4%BB%B6%E5%B8%82%E5%9C%BA&hmpl=&hmcu=&hmkw=&hmci=) 18 | 19 | ## vue-admin-beautiful 前端讨论群-1 972435319 20 | 21 | 不管您加或者不加,您都可以享受到开源的代码,感谢您的支持和信任,群内提供 vue-admin-beautiful-template 基础版本和详细的基础使用文档适合框架快速入门 22 | 23 | ![img](https://chu1204505056.gitee.io/byui-bookmarks/img/ewm.png) 24 | 25 | 26 | 27 | ## 开发者评级 28 | 29 | [![chuzhixin's github stats](https://github-readme-stats.vercel.app/api?username=chuzhixin)](https://github.com/chuzhixin/vue-admin-beautiful) 30 | -------------------------------------------------------------------------------- /common/demo.scss: -------------------------------------------------------------------------------- 1 | /* #ifndef APP-NVUE */ 2 | view, 3 | text { 4 | box-sizing: border-box; 5 | } 6 | /* #endif */ 7 | 8 | /* start--演示页面使用的统一样式--start */ 9 | .u-demo { 10 | padding: 50rpx 40rpx; 11 | } 12 | 13 | .u-demo-wrap { 14 | border-width: 1px; 15 | border-color: #ddd; 16 | border-style: dashed; 17 | background-color: rgb(250, 250, 250); 18 | padding: 40rpx 20rpx; 19 | border-radius: 6px; 20 | } 21 | 22 | .u-demo-area { 23 | text-align: center; 24 | } 25 | 26 | .u-no-demo-here { 27 | color: $u-tips-color; 28 | font-size: 26rpx; 29 | } 30 | 31 | .u-demo-result-line { 32 | border-width: 1px; 33 | border-color: #ddd; 34 | border-style: dashed; 35 | padding: 10rpx 40rpx; 36 | margin-top: 30rpx; 37 | border-radius: 5px; 38 | background-color: rgb(240, 240, 240); 39 | color: $u-content-color; 40 | font-size: 32rpx; 41 | /* #ifndef APP-NVUE */ 42 | word-break: break-word; 43 | display: inline-block; 44 | /* #endif */ 45 | text-align: left; 46 | 47 | } 48 | 49 | .u-demo-title, 50 | .u-config-title { 51 | text-align: center; 52 | font-size: 32rpx; 53 | font-weight: bold; 54 | margin-bottom: 40rpx; 55 | } 56 | 57 | .u-config-item { 58 | margin-top: 50rpx; 59 | } 60 | 61 | .u-config-title { 62 | margin-top: 40rpx; 63 | padding-bottom: 10rpx; 64 | } 65 | 66 | .u-item-title { 67 | position: relative; 68 | font-size: 28rpx; 69 | padding-left: 8px; 70 | line-height: 1; 71 | margin-bottom: 22rpx; 72 | } 73 | 74 | .u-item-title:after { 75 | position: absolute; 76 | width: 4px; 77 | top: -1px; 78 | height: 16px; 79 | /* #ifndef APP-NVUE */ 80 | content: ''; 81 | /* #endif */ 82 | left: 0; 83 | border-radius: 10px; 84 | background-color: $u-content-color; 85 | } 86 | /* end--演示页面使用的统一样式--end */ 87 | -------------------------------------------------------------------------------- /common/http.api.js: -------------------------------------------------------------------------------- 1 | // 如果没有通过拦截器配置域名的话,可以在这里写上完整的URL(加上域名部分) 2 | let hotSearchUrl = '/ebapi/store_api/hot_search'; 3 | let indexUrl = '/ebapi/public_api/index'; 4 | 5 | // 此处第二个参数vm,就是我们在页面使用的this,你可以通过vm获取vuex等操作,更多内容详见uView对拦截器的介绍部分: 6 | // https://uviewui.com/js/http.html#%E4%BD%95%E8%B0%93%E8%AF%B7%E6%B1%82%E6%8B%A6%E6%88%AA%EF%BC%9F 7 | const install = (Vue, vm) => { 8 | // 此处没有使用传入的params参数 9 | let getSearch = (params = {}) => vm.$u.get(hotSearchUrl, { 10 | id: 2 11 | }); 12 | 13 | // 此处使用了传入的params参数,一切自定义即可 14 | let getInfo = (params = {}) => vm.$u.post(indexUrl, params); 15 | 16 | // 将各个定义的接口名称,统一放进对象挂载到vm.$u.api(因为vm就是this,也即this.$u.api)下 17 | vm.$u.api = {getSearch, getInfo}; 18 | } 19 | 20 | export default { 21 | install 22 | } -------------------------------------------------------------------------------- /common/http.interceptor.js: -------------------------------------------------------------------------------- 1 | // 这里的vm,就是我们在vue文件里面的this,所以我们能在这里获取vuex的变量,比如存放在里面的token 2 | // 同时,我们也可以在此使用getApp().globalData,如果你把token放在getApp().globalData的话,也是可以使用的 3 | const install = (Vue, vm) => { 4 | Vue.prototype.$u.http.setConfig({ 5 | baseUrl: 'https://api.youzixy.com', 6 | // 如果将此值设置为true,拦截回调中将会返回服务端返回的所有数据response,而不是response.data 7 | // 设置为true后,就需要在this.$u.http.interceptor.response进行多一次的判断,请打印查看具体值 8 | // originalData: true, 9 | // 设置自定义头部content-type 10 | // header: { 11 | // 'content-type': 'xxx' 12 | // } 13 | }); 14 | // 请求拦截,配置Token等参数 15 | Vue.prototype.$u.http.interceptor.request = (config) => { 16 | config.header.Token = 'xxxxxx'; 17 | 18 | // 方式一,存放在vuex的token,假设使用了uView封装的vuex方式,见:https://uviewui.com/components/globalVariable.html 19 | // config.header.token = vm.token; 20 | 21 | // 方式二,如果没有使用uView封装的vuex方法,那么需要使用$store.state获取 22 | // config.header.token = vm.$store.state.token; 23 | 24 | // 方式三,如果token放在了globalData,通过getApp().globalData获取 25 | // config.header.token = getApp().globalData.username; 26 | 27 | // 方式四,如果token放在了Storage本地存储中,拦截是每次请求都执行的,所以哪怕您重新登录修改了Storage,下一次的请求将会是最新值 28 | // const token = uni.getStorageSync('token'); 29 | // config.header.token = token; 30 | 31 | return config; 32 | } 33 | // 响应拦截,判断状态码是否通过 34 | Vue.prototype.$u.http.interceptor.response = (res) => { 35 | // 如果把originalData设置为了true,这里得到将会是服务器返回的所有的原始数据 36 | // 判断可能变成了res.statueCode,或者res.data.code之类的,请打印查看结果 37 | if(res.code == 200) { 38 | // 如果把originalData设置为了true,这里return回什么,this.$u.post的then回调中就会得到什么 39 | return res.data; 40 | } else return false; 41 | } 42 | } 43 | 44 | export default { 45 | install 46 | } -------------------------------------------------------------------------------- /common/locales/en.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // 可以以页面为单位来写,比如首页的内容,写在index字段,个人中心写在center,共同部分写在common部分 3 | components: { 4 | desc: 'Numerous components cover the various requirements of the development process, and the components are rich in functions and compatible with multiple terminals. Let you integrate quickly, out of the box' 5 | }, 6 | js: { 7 | desc: 'Numerous intimate gadgets are a weapon that you can call upon during the development process, allowing you to dart in your hand and pierce the Yang with a hundred steps' 8 | }, 9 | template: { 10 | desc: 'Collection of many commonly used pages and layouts, reducing the repetitive work of developers, allowing you to focus on logic and get twice the result with half the effort' 11 | }, 12 | nav: { 13 | components: 'Comonents', 14 | js: 'JS', 15 | template: 'Template' 16 | }, 17 | common: { 18 | intro: 'UI framework for rapid development of multiple platforms', 19 | title: 'uView UI', 20 | }, 21 | } -------------------------------------------------------------------------------- /common/locales/zh.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // 可以以页面为单位来写,比如首页的内容,写在index字段,个人中心写在center,共同部分写在common部分 3 | components: { 4 | desc: '众多组件覆盖开发过程的各个需求,组件功能丰富,多端兼容。让你快速集成,开箱即用' 5 | }, 6 | js: { 7 | desc: '众多的贴心小工具,是你开发过程中召之即来的利器,让你飞镖在手,百步穿杨' 8 | }, 9 | template: { 10 | desc: '收集众多的常用页面和布局,减少开发者的重复工作,让你专注逻辑,事半功倍' 11 | }, 12 | nav: { 13 | components: '组件', 14 | js: '工具', 15 | template: '模板' 16 | }, 17 | common: { 18 | intro: '多平台快速开发的UI框架', 19 | title: 'uView UI', 20 | }, 21 | } -------------------------------------------------------------------------------- /components/page-nav/page-nav.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 47 | 48 | 99 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | 4 | Vue.config.productionTip = false 5 | 6 | App.mpType = 'app' 7 | 8 | // 此处为演示Vue.prototype使用,非uView的功能部分 9 | Vue.prototype.vuePrototype = '' 10 | 11 | // 引入全局uView 12 | import uView from 'uview-ui' 13 | Vue.use(uView) 14 | 15 | // 此处为演示vuex使用,非uView的功能部分 16 | import store from '@/store' 17 | 18 | // 引入uView提供的对vuex的简写法文件 19 | let vuexStore = require('@/store/$u.mixin.js') 20 | Vue.mixin(vuexStore) 21 | 22 | // 引入uView对小程序分享的mixin封装 23 | let mpShare = require('uview-ui/libs/mixin/mpShare.js'); 24 | Vue.mixin(mpShare) 25 | 26 | // i18n部分的配置 27 | // 引入语言包,注意路径 28 | import Chinese from '@/common/locales/zh.js'; 29 | import English from '@/common/locales/en.js'; 30 | 31 | // VueI18n 32 | import VueI18n from './common/vue-i18n.min.js' 33 | 34 | // VueI18n 35 | Vue.use(VueI18n) 36 | 37 | const i18n = new VueI18n({ 38 | // 默认语言 39 | locale: 'zh', 40 | // 引入语言文件 41 | messages: { 42 | 'zh': Chinese, 43 | 'en': English, 44 | } 45 | }) 46 | 47 | // 由于微信小程序的运行机制问题,需声明如下一行,H5和APP非必填 48 | Vue.prototype._i18n = i18n 49 | 50 | const app = new Vue({ 51 | i18n, 52 | store, 53 | ...App 54 | }) 55 | 56 | // http拦截器,将此部分放在new Vue()和app.$mount()之间,才能App.vue中正常使用 57 | import httpInterceptor from '@/common/http.interceptor.js' 58 | Vue.use(httpInterceptor, app) 59 | 60 | // http接口API抽离,免于写url或者一些固定的参数 61 | import httpApi from '@/common/http.api.js' 62 | Vue.use(httpApi, app) 63 | 64 | app.$mount() 65 | -------------------------------------------------------------------------------- /pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "easycom": { 3 | "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue" 4 | }, 5 | "pages": [{ 6 | "path": "pages/index/index", 7 | "style": { 8 | "navigationStyle": "custom" 9 | } 10 | }, { 11 | "path": "pages/classifications/index", 12 | "style": { 13 | "navigationBarTitleText": "分类" 14 | } 15 | }, { 16 | "path": "pages/shoppingCart/index", 17 | "style": { 18 | "navigationBarTitleText": "购物车" 19 | } 20 | }, { 21 | "path": "pages/my/index", 22 | "style": { 23 | "navigationBarTitleText": "我的" 24 | } 25 | }, { 26 | "path": "pages/my/address", 27 | "style": { 28 | "navigationBarTitleText": "收货地址" 29 | } 30 | }, { 31 | "path": "pages/my/addSite", 32 | "style": { 33 | "navigationBarTitleText": "添加收货地址" 34 | } 35 | }], 36 | "globalStyle": { 37 | "navigationBarTextStyle": "black", 38 | "navigationBarTitleText": "vue-mall-beautiful", 39 | "navigationBarBackgroundColor": "#FFFFFF", 40 | "backgroundColor": "#FFFFFF" 41 | }, 42 | "tabBar": { 43 | "color": "#909399", 44 | "selectedColor": "#ff3131", 45 | "backgroundColor": "#FFFFFF", 46 | "borderStyle": "black", 47 | "list": [{ 48 | "pagePath": "pages/index/index", 49 | "iconPath": "static/navs/index.png", 50 | "selectedIconPath": "static/navs/index_select.png", 51 | "text": "首页" 52 | }, { 53 | "pagePath": "pages/classifications/index", 54 | "iconPath": "static/navs/classifications.png", 55 | "selectedIconPath": "static/navs/classifications_select.png", 56 | "text": "分类" 57 | }, { 58 | "pagePath": "pages/shoppingCart/index", 59 | "iconPath": "static/navs/shoppingCart.png", 60 | "selectedIconPath": "static/navs/shoppingCart_select.png", 61 | "text": "购物车" 62 | }, { 63 | "pagePath": "pages/my/index", 64 | "iconPath": "static/navs/my.png", 65 | "selectedIconPath": "static/navs/my_select.png", 66 | "text": "我的" 67 | }] 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /pages/index/swiper.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 31 | -------------------------------------------------------------------------------- /pages/my/addSite.vue: -------------------------------------------------------------------------------- 1 |