├── .browserslistrc ├── public ├── favicon.ico └── index.html ├── babel.config.js ├── src ├── assets │ ├── img │ │ ├── common │ │ │ ├── top.png │ │ │ ├── placeholder.png │ │ │ ├── arrow-left.svg │ │ │ ├── back.svg │ │ │ └── collect.svg │ │ ├── profile │ │ │ ├── timg.gif │ │ │ ├── message.svg │ │ │ ├── avatar.svg │ │ │ ├── phone.svg │ │ │ ├── pointer.svg │ │ │ ├── cart.svg │ │ │ ├── vip.svg │ │ │ └── shopping.svg │ │ ├── home │ │ │ └── recommend_bg.jpg │ │ ├── detail │ │ │ └── detail_bottom.png │ │ ├── cart │ │ │ └── tick.svg │ │ └── tabbar │ │ │ ├── shopcart.svg │ │ │ ├── shopcart_active.svg │ │ │ ├── category.svg │ │ │ ├── category_active.svg │ │ │ ├── profile.svg │ │ │ ├── home.svg │ │ │ ├── profile_active.svg │ │ │ └── home_active.svg │ └── css │ │ ├── base.css │ │ └── normalize.css ├── store │ ├── mutation-types.js │ ├── getters.js │ ├── index.js │ ├── actions.js │ └── mutations.js ├── components │ ├── common │ │ ├── swiper │ │ │ ├── index.js │ │ │ ├── SwiperItem.vue │ │ │ └── Swiper.vue │ │ ├── toast │ │ │ ├── index.js │ │ │ └── Toast.vue │ │ ├── tabbar │ │ │ ├── TabBar.vue │ │ │ └── TabBarItem.vue │ │ ├── navbar │ │ │ └── NavBar.vue │ │ ├── scroll │ │ │ └── Scroll.vue │ │ └── gridview │ │ │ └── GridView.vue │ └── content │ │ ├── backTop │ │ └── BackTop.vue │ │ ├── goods │ │ ├── GoodsList.vue │ │ └── GoodsListItem.vue │ │ ├── checkButton │ │ └── CheckButton.vue │ │ ├── tabControl │ │ └── TabControl.vue │ │ └── maintabbar │ │ └── MainTabBar.vue ├── common │ ├── const.js │ ├── utils.js │ └── mixin.js ├── network │ ├── home.js │ ├── request.js │ ├── category.js │ └── detail.js ├── views │ ├── home │ │ ├── childComps │ │ │ ├── FeatureView.vue │ │ │ ├── RecommendView.vue │ │ │ └── HomeSwiper.vue │ │ └── Home.vue │ ├── detail │ │ ├── childComponents │ │ │ ├── detailSwiper.vue │ │ │ ├── DetailNavBar.vue │ │ │ ├── DetailParamInfo.vue │ │ │ ├── DetailBottomBar.vue │ │ │ ├── DetailGoodsInfo.vue │ │ │ ├── DetailBaseInfo.vue │ │ │ ├── DetailCommentInfo.vue │ │ │ └── DetailShopInfo.vue │ │ └── Detail.vue │ ├── cart │ │ ├── childComps │ │ │ ├── CartList.vue │ │ │ ├── CartListItem.vue │ │ │ └── CartBottomBar.vue │ │ └── Cart.vue │ ├── profile │ │ ├── childComponents │ │ │ ├── UserInfo.vue │ │ │ ├── AccountInfo.vue │ │ │ └── NormalListView.vue │ │ └── Profile.vue │ └── category │ │ ├── childComponents │ │ ├── CategoryContent.vue │ │ └── CategoryMenu.vue │ │ └── Category.vue ├── App.vue ├── main.js └── router │ └── index.js ├── .editorconfig ├── .gitignore ├── README.md ├── postcss.config.js ├── package.json ├── SECURITY.md ├── vue.config.js ├── LICENSE └── Vue响应式原理.html /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudufu/supermall/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/img/common/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudufu/supermall/HEAD/src/assets/img/common/top.png -------------------------------------------------------------------------------- /src/assets/img/profile/timg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudufu/supermall/HEAD/src/assets/img/profile/timg.gif -------------------------------------------------------------------------------- /src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const ADD_COUNTER = 'add_counter'; 2 | export const ADD_TO_CART = 'add_to_cart'; 3 | -------------------------------------------------------------------------------- /src/assets/img/common/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudufu/supermall/HEAD/src/assets/img/common/placeholder.png -------------------------------------------------------------------------------- /src/assets/img/home/recommend_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudufu/supermall/HEAD/src/assets/img/home/recommend_bg.jpg -------------------------------------------------------------------------------- /src/assets/img/detail/detail_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudufu/supermall/HEAD/src/assets/img/detail/detail_bottom.png -------------------------------------------------------------------------------- /src/components/common/swiper/index.js: -------------------------------------------------------------------------------- 1 | import Swiper from './Swiper' 2 | import SwiperItem from './SwiperItem' 3 | 4 | export { 5 | Swiper, SwiperItem 6 | } 7 | -------------------------------------------------------------------------------- /src/common/const.js: -------------------------------------------------------------------------------- 1 | //滚动到TOP_DISTANCE 位置显示回到顶部按钮 2 | export const TOP_DISTANCE = 2000 3 | export const POP = 'pop' 4 | export const NEW = 'new' 5 | export const SELL = 'sell' 6 | -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- 1 | export default { 2 | cartLength(state) { 3 | return state.cartList.length; 4 | }, 5 | cartList(state) { 6 | return state.cartList; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /src/components/common/swiper/SwiperItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /src/assets/img/cart/tick.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/network/home.js: -------------------------------------------------------------------------------- 1 | import {request} from "./request"; 2 | 3 | export function getHomeMultidata() { 4 | return request({ 5 | url: '/home/multidata' 6 | // url: '/test/getBanners' 7 | }) 8 | } 9 | 10 | export function getHomeGoods(type, page) { 11 | return request({ 12 | url: '/home/data', 13 | // url: '/test/getGoods', 14 | params: { 15 | type, 16 | page 17 | } 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/views/home/childComps/FeatureView.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from 'vuex'; 3 | 4 | import mutations from "./mutations"; 5 | import actions from "./actions"; 6 | import getters from "./getters"; 7 | //1、安装插件 8 | Vue.use(Vuex) 9 | 10 | //2、创建store对象 11 | const state = { 12 | cartList: [] 13 | } 14 | 15 | const store = new Vuex.Store({ 16 | state, 17 | mutations, 18 | actions, 19 | getters 20 | }) 21 | 22 | //3、导出 23 | export default store 24 | -------------------------------------------------------------------------------- /src/components/content/backTop/BackTop.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 24 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # supermall 2 | 3 | ## 项目简介 4 | 5 | ​ 本项目是根据蘑菇街App的手机端页面做的整体布局。 6 | 7 | ​ 功能有:主页包括浏览商品、上拉刷新下拉加载更多商品等功能。详情页包括商品的展示,以及商品的参数,评论,店家信息,还有加入购物车功能等。分类页面包括商品的分类展示,分类查看。购物车页面是管理添加的商品,是用Vuex保存的数据,并没有提交到数据库。 8 | 9 | ## 初始化项目 10 | ``` 11 | npm install 12 | ``` 13 | 14 | ### 运行项目 15 | ``` 16 | npm run serve 17 | ``` 18 | 19 | ### 打包项目 20 | ``` 21 | npm run build 22 | ``` 23 | 24 | ### 自定义配置 25 | 参照 [Configuration Reference](https://cli.vuejs.org/config/). 26 | 27 | ### 提示 28 | 如果接口失效,请联系微信coderwhy003获取新接口 29 | -------------------------------------------------------------------------------- /src/assets/img/common/arrow-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | "postcss-px-to-viewport": { 5 | viewportWidth: 375, // 视窗的宽度,对应的是我们设计稿的宽度. 6 | viewportHeight: 667, // 视窗的高度,对应的是我们设计稿的高度.(也可以不配置) 7 | unitPrecision: 5, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除) 8 | viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用vw 9 | selectorBlackList: ['tab-bar', 'tab-bar-item','cart-bottom-bar'], // 指定不需要转换的类 10 | minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位. 11 | mediaQuery: false // 允许在媒体查询中转换`px` 12 | }, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/img/common/back.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/common/toast/index.js: -------------------------------------------------------------------------------- 1 | import Toast from "./Toast"; 2 | 3 | const obj = { 4 | 5 | } 6 | 7 | obj.install = function (Vue) { 8 | // document.body.appendChild(Toast.$el) 9 | //1、创建组件构造器 10 | const toastConstructor = Vue.extend(Toast); 11 | 12 | //2、new的方式,根据组件构造器,可以创建出来一个组件对象 13 | const toast = new toastConstructor(); 14 | //3、将组价对象,手动挂载到某一个元素上 15 | toast.$mount(document.createElement('div')); 16 | 17 | //4、toast.$el对应的就是div 18 | document.body.appendChild(toast.$el); 19 | 20 | Vue.prototype.$toast = toast; 21 | } 22 | 23 | export default obj 24 | -------------------------------------------------------------------------------- /src/components/common/tabbar/TabBar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/network/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | export function request(config) { 4 | // 1.创建axios的实例 5 | const instance = axios.create({ 6 | baseURL: 'http://123.207.32.32:8000', 7 | 8 | //baseURL: 'http://adi-v3.dev', 9 | timeout: 5000 10 | }) 11 | 12 | // 2.axios的拦截器 13 | // 2.1.请求拦截的作用 14 | instance.interceptors.request.use(config => { 15 | return config 16 | }, err => { 17 | // console.log(err); 18 | }) 19 | 20 | // 2.2.响应拦截 21 | instance.interceptors.response.use(res => { 22 | return res.data 23 | }, err => { 24 | console.log(err); 25 | }) 26 | 27 | // 3.发送真正的网络请求 28 | return instance(config) 29 | } 30 | -------------------------------------------------------------------------------- /src/components/common/navbar/NavBar.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "supermall", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "axios": "^0.21.2", 11 | "better-scroll": "^1.15.2", 12 | "core-js": "^3.6.5", 13 | "fastclick": "^1.0.6", 14 | "vue": "^2.6.11", 15 | "vue-lazyload": "^1.3.3", 16 | "vue-router": "^3.3.4", 17 | "vuex": "^3.5.1" 18 | }, 19 | "devDependencies": { 20 | "@vue/cli-plugin-babel": "~4.4.0", 21 | "@vue/cli-service": "~4.4.0", 22 | "postcss-px-to-viewport": "^1.1.1", 23 | "vue-template-compiler": "^2.6.11" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from "./store"; 5 | 6 | import FastClick from 'fastclick'; 7 | import VueLazyload from "vue-lazyload"; 8 | 9 | import toast from 'components/common/toast' 10 | 11 | Vue.config.productionTip = false 12 | 13 | Vue.prototype.$bus = new Vue() 14 | 15 | //安装toast插件 16 | Vue.use(toast) 17 | 18 | //解决移动端三百毫秒的延迟 19 | FastClick.attach(document.body); 20 | 21 | //使用懒加载的插件(需要将使用懒加载的图片路径改为src->v-lazy) 22 | Vue.use(VueLazyload, { 23 | loading: require('assets/img/common/placeholder.png') 24 | }); 25 | 26 | new Vue({ 27 | render: h => h(App), 28 | router, 29 | store 30 | }).$mount('#app') 31 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /src/components/content/goods/GoodsList.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | 26 | 37 | -------------------------------------------------------------------------------- /src/views/detail/childComponents/detailSwiper.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 28 | 29 | 35 | -------------------------------------------------------------------------------- /src/store/actions.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_COUNTER, 3 | ADD_TO_CART 4 | } from './mutation-types'; 5 | 6 | export default { 7 | addCart(context, payload) { 8 | return new Promise((resolve, reject) => { 9 | //payload新加入的商品 10 | //1、查找数组中是否有该商品 11 | let product = context.state.cartList.find((item) => { 12 | return item.iid === payload.iid; 13 | }); 14 | //2、判断product 15 | if(product) { 16 | // product.count += 1; 17 | context.commit(ADD_COUNTER, product); 18 | resolve('当前的商品数量加一'); 19 | }else { 20 | payload.count = 1; 21 | // context.state.cartList.push(payload); 22 | context.commit(ADD_TO_CART, payload); 23 | resolve('添加了心得商品'); 24 | } 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/network/category.js: -------------------------------------------------------------------------------- 1 | import {request} from "./request"; 2 | 3 | /** 4 | * 获取分类的数据 5 | * @returns {AxiosPromise} 6 | */ 7 | export function getCategory() { 8 | return request({ 9 | url: '/category' 10 | }) 11 | } 12 | 13 | /** 14 | * 获取每个分类栏的数据 15 | * @param maitKey 16 | * @returns {AxiosPromise} 17 | */ 18 | export function getSubcategory(maitKey) { 19 | return request({ 20 | url: '/subcategory', 21 | params: { 22 | maitKey 23 | } 24 | }) 25 | } 26 | 27 | /** 28 | * 获取每个分类里面的商品信息 29 | * @param miniWallkey 30 | * @param type 31 | * @returns {AxiosPromise} 32 | */ 33 | export function getCategoryDetail(miniWallkey, type) { 34 | return request({ 35 | url: '/subcategory/detail', 36 | params: { 37 | miniWallkey, 38 | type 39 | } 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | // module.exports = { 2 | // configureWebpack: { 3 | // resolve: { 4 | // alias:{ 5 | // 'assets': 'src/assets', 6 | // 'common': 'src/common', 7 | // 'components': 'src/components', 8 | // 'network': 'src/network', 9 | // 'views': 'src/views' 10 | // } 11 | // } 12 | // } 13 | // } 14 | const path = require('path'); 15 | 16 | function resolve(dir) { 17 | return path.join(__dirname, dir) 18 | } 19 | 20 | module.exports = { 21 | chainWebpack:(config) => { 22 | config.resolve.alias 23 | .set('@', resolve('./src')) 24 | .set('assets', resolve('./src/assets')) 25 | .set('common', resolve('./src/common')) 26 | .set('components', resolve('./src/components')) 27 | .set('network', resolve('./src/network')) 28 | .set('views', resolve('./src/views')) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/assets/img/tabbar/shopcart.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/views/home/childComps/RecommendView.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | 26 | 45 | -------------------------------------------------------------------------------- /src/assets/img/tabbar/shopcart_active.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | 3 | import vueRouter from 'vue-router'; 4 | 5 | const Home = () => import('../views/home/Home') 6 | const Category = () => import('../views/category/Category') 7 | const Cart = () => import('../views/cart/Cart') 8 | const Profile = () => import('../views/profile/Profile') 9 | const Detail = () => import('../views/detail/Detail') 10 | //安装插件 11 | Vue.use(vueRouter) 12 | 13 | //创建路由对象 14 | const routes = [ 15 | { 16 | path: '', 17 | redirect: '/home' 18 | }, 19 | { 20 | path: '/home', 21 | component: Home 22 | }, 23 | { 24 | path: '/category', 25 | component: Category 26 | }, 27 | { 28 | path: '/cart', 29 | component: Cart 30 | }, 31 | { 32 | path: '/profile', 33 | component: Profile 34 | }, 35 | { 36 | path: '/detail/:iid', 37 | component: Detail 38 | } 39 | ] 40 | const router = new vueRouter({ 41 | routes, 42 | code: 'history' 43 | }) 44 | 45 | export default router 46 | -------------------------------------------------------------------------------- /src/components/content/checkButton/CheckButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 21 | 43 | -------------------------------------------------------------------------------- /src/assets/img/tabbar/category.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 14 | 16 | 18 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/assets/img/tabbar/category_active.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 14 | 16 | 18 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/assets/img/tabbar/profile.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/img/tabbar/home.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/img/tabbar/profile_active.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/img/profile/message.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/tabbar/home_active.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/common/utils.js: -------------------------------------------------------------------------------- 1 | //debounce 防抖动 2 | export function debounce(func, delay){ 3 | let timer = null; 4 | 5 | return function (...args) { 6 | if(timer) { 7 | clearTimeout(timer); 8 | } 9 | timer = setTimeout(() => { 10 | func.apply(this, args); 11 | }, delay) 12 | } 13 | }; 14 | 15 | // 时间戳转换 16 | export function formatDate(date, fmt) { 17 | //1、获取年份 18 | if (/(y+)/.test(fmt)) { 19 | fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); 20 | } 21 | //2、获取 22 | let o = { 23 | 'M+': date.getMonth() + 1, 24 | 'd+': date.getDate(), 25 | 'h+': date.getHours(), 26 | 'm+': date.getMinutes(), 27 | 's+': date.getSeconds() 28 | }; 29 | for (let k in o) { 30 | if (new RegExp(`(${k})`).test(fmt)) { 31 | let str = o[k] + ''; 32 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str)); 33 | } 34 | } 35 | return fmt; 36 | }; 37 | 38 | function padLeftZero (str) { 39 | return ('00' + str).substr(str.length); 40 | }; 41 | -------------------------------------------------------------------------------- /src/views/home/childComps/HomeSwiper.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 44 | 45 | 48 | -------------------------------------------------------------------------------- /src/views/cart/childComps/CartList.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 31 | 32 | 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 liudufu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/common/toast/Toast.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 39 | 40 | 53 | -------------------------------------------------------------------------------- /src/views/cart/Cart.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 42 | 43 | 54 | -------------------------------------------------------------------------------- /src/network/detail.js: -------------------------------------------------------------------------------- 1 | import {request} from "./request"; 2 | 3 | export function getDetail(iid) { 4 | return request({ 5 | url: '/detail', 6 | params: { 7 | iid 8 | } 9 | }) 10 | } 11 | 12 | export function getRecommend() { 13 | return request({ 14 | url: '/recommend' 15 | }) 16 | } 17 | 18 | export class Goods { 19 | constructor(itemInfo, colums, services) { 20 | this.title = itemInfo.title; 21 | this.desc = itemInfo.desc; 22 | this.newPrice = itemInfo.price; 23 | this.oldPrice = itemInfo.oldPrice; 24 | this.discount = itemInfo.discount; 25 | this.columns = colums; 26 | this.services = services; 27 | this.realPrice = itemInfo.lowNowPrice; 28 | } 29 | } 30 | 31 | export class GoodsParam { 32 | constructor(info, rule) { 33 | //注:images可能没有值 34 | this.image = info.images ? info.images[0] : ''; 35 | this.infos = info.set; 36 | this.sizes = rule.tables; 37 | } 38 | } 39 | 40 | export class Shop { 41 | constructor(shopInfo) { 42 | this.logo = shopInfo.shopLogo; 43 | this.name = shopInfo.name; 44 | this.fans = shopInfo.cFans; 45 | this.sells = shopInfo.cSells; 46 | this.score = shopInfo.score; 47 | this.goodsCount = shopInfo.cGoods; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/components/content/tabControl/TabControl.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 36 | 37 | 62 | -------------------------------------------------------------------------------- /src/views/profile/childComponents/UserInfo.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 67 | -------------------------------------------------------------------------------- /src/views/profile/childComponents/AccountInfo.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 29 | 30 | 61 | -------------------------------------------------------------------------------- /src/views/detail/childComponents/DetailNavBar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 45 | 46 | 62 | -------------------------------------------------------------------------------- /src/views/profile/Profile.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 43 | 44 | 54 | -------------------------------------------------------------------------------- /src/views/category/childComponents/CategoryContent.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 45 | 46 | 64 | -------------------------------------------------------------------------------- /src/store/mutations.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_COUNTER, 3 | ADD_TO_CART 4 | } from './mutation-types' 5 | 6 | export default { 7 | //mutation唯一的目的,修改state中的状态 8 | //但是mutation方法规则是比较单一的,一个方法只做一件事情,所以addCart方法应放到actions中 9 | // addCart(state, payload) { 10 | // } 11 | [ADD_COUNTER](state, payload) { 12 | payload.count++; 13 | }, 14 | [ADD_TO_CART](state, payload) { 15 | payload.checked = true; 16 | state.cartList.push(payload); 17 | }, 18 | /** 19 | * 更新商品中Checked的值 20 | */ 21 | updateChecked(state, payload) { 22 | //1、查找到当前要修改的商品 23 | let oldProduct = state.cartList.find(item => { 24 | return item.iid === payload.item.iid && item.productStyleMsg === payload.item.productStyleMsg && item.productSizeMsg === payload.item.productSizeMsg 25 | }) 26 | //2、改变checked值 27 | oldProduct.checked = payload.checked; 28 | }, 29 | 30 | /** 31 | * 更新商品中currentCounts的值 32 | */ 33 | updateCounts(state, payload) { 34 | //1、查找到当前要修改的商品 35 | let oldProduct = state.cartList.find(item => { 36 | return item.iid === payload.item.iid && item.productStyleMsg === payload.item.productStyleMsg && item.productSizeMsg === payload.item.productSizeMsg 37 | }) 38 | //2、改变checked值 39 | oldProduct.currentCounts += payload.number; 40 | }, 41 | /** 42 | * 删除选中的商品 43 | */ 44 | deleteProduct(state) { 45 | state.cartList = state.cartList.filter(item => !item.checked); 46 | } 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/views/profile/childComponents/NormalListView.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 30 | 31 | 67 | -------------------------------------------------------------------------------- /src/views/category/childComponents/CategoryMenu.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 38 | 39 | 62 | -------------------------------------------------------------------------------- /src/assets/css/base.css: -------------------------------------------------------------------------------- 1 | @import "./normalize.css"; 2 | /*:root -> 获取根元素html*/ 3 | :root { 4 | /* --color-text 意思 是 定义变量 */ 5 | --color-text: #666; 6 | --color-high-text: #ff5777; 7 | --color-tint: #ff8198;/* */ 8 | --color-background: #fff; 9 | --font-size: 14px; 10 | --line-height: 1.5; 11 | } 12 | 13 | *, 14 | *::before, 15 | *::after { 16 | margin: 0; 17 | padding: 0; 18 | box-sizing: border-box; 19 | } 20 | 21 | body { 22 | font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; 23 | user-select: none; /* 禁止用户鼠标在页面上选中文字/图片等 */ 24 | -webkit-tap-highlight-color: transparent; /* webkit是苹果浏览器引擎,tap点击,highlight背景高亮,color颜色,颜色用数值调节 */ 25 | background: var(--color-background); 26 | color: var(--color-text); 27 | width: 100vw; 28 | } 29 | 30 | a { 31 | color: var(--color-text); 32 | text-decoration: none; 33 | } 34 | 35 | 36 | .clear-fix::after { 37 | clear: both; 38 | content: ''; 39 | display: block; 40 | width: 0; 41 | height: 0; 42 | visibility: hidden; 43 | } 44 | 45 | .clear-fix { 46 | zoom: 1; 47 | } 48 | 49 | .arrow-right { 50 | border-top: 1px solid #999; 51 | border-left: 1px solid #999; 52 | width: 9px; 53 | height: 9px; 54 | background-color: transparent; 55 | transform: rotate(135deg); 56 | display: inline-block; 57 | margin-left: .1rem; 58 | } 59 | 60 | .left { 61 | float: left; 62 | } 63 | 64 | .right { 65 | float: right; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/assets/img/profile/avatar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/content/maintabbar/MainTabBar.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /src/assets/img/profile/phone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/detail/childComponents/DetailParamInfo.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 35 | 36 | 73 | -------------------------------------------------------------------------------- /src/components/common/scroll/Scroll.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 71 | 72 | 75 | -------------------------------------------------------------------------------- /src/components/common/gridview/GridView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 65 | 66 | 73 | -------------------------------------------------------------------------------- /src/views/detail/childComponents/DetailBottomBar.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 35 | 36 | 99 | -------------------------------------------------------------------------------- /src/assets/img/common/collect.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/common/mixin.js: -------------------------------------------------------------------------------- 1 | import {debounce} from "./utils"; 2 | 3 | import BackTop from "components/content/backTop/BackTop"; 4 | import TabControl from "components/content/tabControl/TabControl"; 5 | import {POP, SELL, NEW} from "./const"; 6 | 7 | export const itemListener = { 8 | data() { 9 | return { 10 | itemImgListener: null, 11 | refresh: null 12 | } 13 | }, 14 | mounted() { 15 | this.refresh = debounce(this.$refs.scroll.refresh, 500); 16 | this.itemImgListener = () => { 17 | this.refresh() 18 | }; 19 | this.$bus.$on('itemImgLoad', this.itemImgListener); 20 | console.log('mounted混入操作'); 21 | } 22 | } 23 | 24 | export const backTopMinxin = { 25 | components: { 26 | BackTop 27 | }, 28 | data() { 29 | return { 30 | isShowBackTop: false 31 | } 32 | }, 33 | methods: { 34 | backClick() { 35 | this.$refs.scroll.scrollTo(0, 0) 36 | }, 37 | } 38 | } 39 | /** 40 | * tabControl导航栏的公共代码 41 | * @type {{data: (function(): {currentType: string}), methods: {tabClick(*): void}}} 42 | */ 43 | export const tabControlMixin = { 44 | components: { 45 | TabControl 46 | }, 47 | data() { 48 | return { 49 | currentType: POP 50 | } 51 | }, 52 | methods: { 53 | //1、监听tabControl的点击 54 | tabClick(index) { 55 | //调用此方法来保持两个tabControl的选项一致 56 | this._tabClick(index); 57 | 58 | switch (index) { 59 | case 0: 60 | //如果当前页面不是正在显示的就滚动到所点击标签的起始位置 61 | if (this.currentType != POP && this.isTabFixed) { 62 | this.$refs.scroll && this.$refs.scroll.scrollTo(0, (-this.tabOffsetTop), 0); 63 | } 64 | this.currentType = POP; 65 | break; 66 | 67 | case 1: 68 | if (this.currentType != NEW && this.isTabFixed) { 69 | this.$refs.scroll && this.$refs.scroll.scrollTo(0, (-this.tabOffsetTop), 0); 70 | } 71 | this.currentType = NEW; 72 | break; 73 | 74 | case 2: 75 | if (this.currentType != SELL && this.isTabFixed) { 76 | this.$refs.scroll && this.$refs.scroll.scrollTo(0, (-this.tabOffsetTop), 0); 77 | } 78 | this.currentType = SELL; 79 | break; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/assets/img/profile/pointer.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/profile/cart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/content/goods/GoodsListItem.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 46 | 47 | 96 | -------------------------------------------------------------------------------- /Vue响应式原理.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 16 | 17 | 18 |
19 | {{message}} 20 | {{message}} 21 | {{message}} 22 |
23 | 24 | 91 | 92 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/views/cart/childComps/CartListItem.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 46 | 47 | 107 | -------------------------------------------------------------------------------- /src/views/detail/childComponents/DetailGoodsInfo.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 53 | 54 | 106 | -------------------------------------------------------------------------------- /src/views/detail/childComponents/DetailBaseInfo.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 38 | 39 | 102 | -------------------------------------------------------------------------------- /src/assets/img/profile/vip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/detail/childComponents/DetailCommentInfo.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 49 | 50 | 122 | -------------------------------------------------------------------------------- /src/assets/img/profile/shopping.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/common/tabbar/TabBarItem.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 62 | 63 | 94 | 95 | 113 | -------------------------------------------------------------------------------- /src/views/detail/childComponents/DetailShopInfo.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 64 | 65 | 163 | -------------------------------------------------------------------------------- /src/views/cart/childComps/CartBottomBar.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 114 | 115 | 171 | -------------------------------------------------------------------------------- /src/views/category/Category.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 186 | 187 | 222 | -------------------------------------------------------------------------------- /src/views/home/Home.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 193 | 194 | 238 | -------------------------------------------------------------------------------- /src/components/common/swiper/Swiper.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 211 | 212 | 246 | -------------------------------------------------------------------------------- /src/assets/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Correct the font size and margin on `h1` elements within `section` and 29 | * `article` contexts in Chrome, Firefox, and Safari. 30 | */ 31 | 32 | h1 { 33 | font-size: 2em; 34 | margin: 0.67em 0; 35 | } 36 | 37 | /* Grouping content 38 | ========================================================================== */ 39 | 40 | /** 41 | * 1. Add the correct box sizing in Firefox. 42 | * 2. Show the overflow in Edge and IE. 43 | */ 44 | 45 | hr { 46 | box-sizing: content-box; /* 1 */ 47 | height: 0; /* 1 */ 48 | overflow: visible; /* 2 */ 49 | } 50 | 51 | /** 52 | * 1. Correct the inheritance and scaling of font size in all browsers. 53 | * 2. Correct the odd `em` font sizing in all browsers. 54 | */ 55 | 56 | pre { 57 | font-family: monospace, monospace; /* 1 */ 58 | font-size: 1em; /* 2 */ 59 | } 60 | 61 | /* Text-level semantics 62 | ========================================================================== */ 63 | 64 | /** 65 | * Remove the gray background on active links in IE 10. 66 | */ 67 | 68 | a { 69 | background-color: transparent; 70 | } 71 | 72 | /** 73 | * 1. Remove the bottom border in Chrome 57- 74 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 75 | */ 76 | 77 | abbr[title] { 78 | border-bottom: none; /* 1 */ 79 | text-decoration: underline; /* 2 */ 80 | text-decoration: underline dotted; /* 2 */ 81 | } 82 | 83 | /** 84 | * Add the correct font weight in Chrome, Edge, and Safari. 85 | */ 86 | 87 | b, 88 | strong { 89 | font-weight: bolder; 90 | } 91 | 92 | /** 93 | * 1. Correct the inheritance and scaling of font size in all browsers. 94 | * 2. Correct the odd `em` font sizing in all browsers. 95 | */ 96 | 97 | code, 98 | kbd, 99 | samp { 100 | font-family: monospace, monospace; /* 1 */ 101 | font-size: 1em; /* 2 */ 102 | } 103 | 104 | /** 105 | * Add the correct font size in all browsers. 106 | */ 107 | 108 | small { 109 | font-size: 80%; 110 | } 111 | 112 | /** 113 | * Prevent `sub` and `sup` elements from affecting the line height in 114 | * all browsers. 115 | */ 116 | 117 | sub, 118 | sup { 119 | font-size: 75%; 120 | line-height: 0; 121 | position: relative; 122 | vertical-align: baseline; 123 | } 124 | 125 | sub { 126 | bottom: -0.25em; 127 | } 128 | 129 | sup { 130 | top: -0.5em; 131 | } 132 | 133 | /* Embedded content 134 | ========================================================================== */ 135 | 136 | /** 137 | * Remove the border on images inside links in IE 10. 138 | */ 139 | 140 | img { 141 | border-style: none; 142 | } 143 | 144 | /* Forms 145 | ========================================================================== */ 146 | 147 | /** 148 | * 1. Change the font styles in all browsers. 149 | * 2. Remove the margin in Firefox and Safari. 150 | */ 151 | 152 | button, 153 | input, 154 | optgroup, 155 | select, 156 | textarea { 157 | font-family: inherit; /* 1 */ 158 | font-size: 100%; /* 1 */ 159 | line-height: 1.15; /* 1 */ 160 | margin: 0; /* 2 */ 161 | } 162 | 163 | /** 164 | * Show the overflow in IE. 165 | * 1. Show the overflow in Edge. 166 | */ 167 | 168 | button, 169 | input { /* 1 */ 170 | overflow: visible; 171 | } 172 | 173 | /** 174 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 175 | * 1. Remove the inheritance of text transform in Firefox. 176 | */ 177 | 178 | button, 179 | select { /* 1 */ 180 | text-transform: none; 181 | } 182 | 183 | /** 184 | * Correct the inability to style clickable types in iOS and Safari. 185 | */ 186 | 187 | button, 188 | [type="button"], 189 | [type="reset"], 190 | [type="submit"] { 191 | -webkit-appearance: button; 192 | } 193 | 194 | /** 195 | * Remove the inner border and padding in Firefox. 196 | */ 197 | 198 | button::-moz-focus-inner, 199 | [type="button"]::-moz-focus-inner, 200 | [type="reset"]::-moz-focus-inner, 201 | [type="submit"]::-moz-focus-inner { 202 | border-style: none; 203 | padding: 0; 204 | } 205 | 206 | /** 207 | * Restore the focus styles unset by the previous rule. 208 | */ 209 | 210 | button:-moz-focusring, 211 | [type="button"]:-moz-focusring, 212 | [type="reset"]:-moz-focusring, 213 | [type="submit"]:-moz-focusring { 214 | outline: 1px dotted ButtonText; 215 | } 216 | 217 | /** 218 | * Correct the padding in Firefox. 219 | */ 220 | 221 | fieldset { 222 | padding: 0.35em 0.75em 0.625em; 223 | } 224 | 225 | /** 226 | * 1. Correct the text wrapping in Edge and IE. 227 | * 2. Correct the color inheritance from `fieldset` elements in IE. 228 | * 3. Remove the padding so developers are not caught out when they zero out 229 | * `fieldset` elements in all browsers. 230 | */ 231 | 232 | legend { 233 | box-sizing: border-box; /* 1 */ 234 | color: inherit; /* 2 */ 235 | display: table; /* 1 */ 236 | max-width: 100%; /* 1 */ 237 | padding: 0; /* 3 */ 238 | white-space: normal; /* 1 */ 239 | } 240 | 241 | /** 242 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 243 | */ 244 | 245 | progress { 246 | vertical-align: baseline; 247 | } 248 | 249 | /** 250 | * Remove the default vertical scrollbar in IE 10+. 251 | */ 252 | 253 | textarea { 254 | overflow: auto; 255 | } 256 | 257 | /** 258 | * 1. Add the correct box sizing in IE 10. 259 | * 2. Remove the padding in IE 10. 260 | */ 261 | 262 | [type="checkbox"], 263 | [type="radio"] { 264 | box-sizing: border-box; /* 1 */ 265 | padding: 0; /* 2 */ 266 | } 267 | 268 | /** 269 | * Correct the cursor style of increment and decrement buttons in Chrome. 270 | */ 271 | 272 | [type="number"]::-webkit-inner-spin-button, 273 | [type="number"]::-webkit-outer-spin-button { 274 | height: auto; 275 | } 276 | 277 | /** 278 | * 1. Correct the odd appearance in Chrome and Safari. 279 | * 2. Correct the outline style in Safari. 280 | */ 281 | 282 | [type="search"] { 283 | -webkit-appearance: textfield; /* 1 */ 284 | outline-offset: -2px; /* 2 */ 285 | } 286 | 287 | /** 288 | * Remove the inner padding in Chrome and Safari on macOS. 289 | */ 290 | 291 | [type="search"]::-webkit-search-decoration { 292 | -webkit-appearance: none; 293 | } 294 | 295 | /** 296 | * 1. Correct the inability to style clickable types in iOS and Safari. 297 | * 2. Change font properties to `inherit` in Safari. 298 | */ 299 | 300 | ::-webkit-file-upload-button { 301 | -webkit-appearance: button; /* 1 */ 302 | font: inherit; /* 2 */ 303 | } 304 | 305 | /* Interactive 306 | ========================================================================== */ 307 | 308 | /* 309 | * Add the correct display in Edge, IE 10+, and Firefox. 310 | */ 311 | 312 | details { 313 | display: block; 314 | } 315 | 316 | /* 317 | * Add the correct display in all browsers. 318 | */ 319 | 320 | summary { 321 | display: list-item; 322 | } 323 | 324 | /* Misc 325 | ========================================================================== */ 326 | 327 | /** 328 | * Add the correct display in IE 10+. 329 | */ 330 | 331 | template { 332 | display: none; 333 | } 334 | 335 | /** 336 | * Add the correct display in IE 10. 337 | */ 338 | 339 | [hidden] { 340 | display: none; 341 | } 342 | -------------------------------------------------------------------------------- /src/views/detail/Detail.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 234 | 235 | 254 | --------------------------------------------------------------------------------