# 全局安裝 vue-cli $ cnpm install --global vue-cli # 建立一個基於 webpack 模板的新項目 $ vue init webpack my-project
# 開發者模式運行[默認訪問:localhost:8080] $ npm run dev # 打包運行[默認訪問:localhost:5000] $ npm run build $ npm install -g serve $ serve dist
src 》api 與後臺交互模塊文件夾 》common 通用資源文件夾,如fonts/img/stylus 》components 非路由組件文件夾 》filter 自定義過濾器模塊文件夾 》mock 模擬數據接口文件夾 》pages 路由組件文件夾 》router 路由器文件夾 》store vuex相關模塊文件夾 - App.vue 入口應用組件 - main.js 入口JS
$ npm install stylus stylus-loader --save-dev # App.vue裏的<style>改爲以下: <style lang='stylus' rel='stylesheet/stylus'>
重置瀏覽器標籤的樣式表:Reset CSS連接
src同目錄下的static文件夾下建立css/reset.css文件
訪問連接並複製裏面的CSS樣式粘貼到reset.css文件中
index.html引入css
<html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>yu-mall</title> <link rel="stylesheet" href="http://at.alicdn.com/t/font_867696_7k42ws2p9ew.css"> <link rel="stylesheet" href="/static/css/reset.css"> </head> <body> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
訪問阿里巴巴圖標庫選擇圖標建立項目後獲取樣式連接html
在index.html文件對應的引入vue
<link rel="dns-prefetch" href="http://at.alicdn.com/t/font_867696_7k42ws2p9ew.css"/>
# 安裝 $ npm install vue-router --save # 建立路由配置JS 路徑:src/router/index.js # index.js代碼塊 import Vue from 'vue' import Router from 'vue-router' import Home from '../pages/Home/Home' import Category from '../pages/Category/Category' import Cart from '../pages/Cart/Cart' import User from '../pages/User/User' Vue.use(Router) export default new Router({ mode: 'history', routes: [ { path: '/', redirect: '/Home' // 重定向到首頁 }, { path: '/Home', component: Home // 首頁 }, { path: '/Category', component: Category // 分類 }, { path: '/Cart', component: Cart // 購物車 }, { path: '/User', component: User // 個人 } ] }) # main.js代碼塊 import Vue from 'vue' import App from './App' import router from './router/index' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
路徑:src/components/FooterGuide/FooterGuide.vuewebpack
<template> <div class="footer-guide"> <div class="guide-item" v-for="guide in guides" :class="{on:guide.path === $route.path}" @click="goTo(guide.path)"> <span class="item-icon"> <i class="iconfont" :class="[guide.path === $route.path ? guide.choice_icon : guide.icon]"></i> </span> <span>{{ guide.text}}</span> </div> </div> </template> <script> export default { name: 'FooterGuide', data () { return { 'guides': [ { text: '首頁', icon: 'icon-home', choice_icon: 'icon-homefill', path: '/home' }, { text: '分類', icon: 'icon-form_light', choice_icon: 'icon-formfill', path: '/category' }, { text: '購物車', icon: 'icon-cart', choice_icon: 'icon-cartfill', path: '/cart' }, { text: '個人', icon: 'icon-people', choice_icon: 'icon-peoplefill', path: '/user' } ] } }, methods: { goTo (path) { this.$router.replace(path) } } } </script> <style lang='stylus' rel='stylesheet/stylus'> @import "../../common/stylus/mixins.styl" /* $hr=1px #EEE solid */ .footer-guide border-top $hr position fixed z-index 100 left 0 bottom 0 background #FFF width 100% height 50px display flex .guide-item text-decoration none display flex flex 1 text-align center flex-direction column align-items center margin 5px color #8a8a8a &.on color #ff001e span font-size 12px margin-top 2px margin-bottom 2px .iconfont font-size 22px </style>
將該組件添加到App.vue中web
<template> <div id="app"> <router-view/> <footer-guide/> </div> </template> <script> import FooterGuide from './components/FooterGuide/FooterGuide' export default { name: 'App', components: { FooterGuide } } </script>
效果圖:vue-router
路徑:src/components/HeaderSearch/HeaderSearch.vuevuex
<template> <div class="header-search"> <div class="search-box"> <a href="/search"><i class="iconfont icon-search"></i><span>請輸入你想找的商品</span></a> </div> </div> </template> <script> export default { name: 'HeaderSearch', data () { return { } } } </script> <style lang="stylus" rel="stylesheet/stylus"> @import "../../common/stylus/mixins.styl" .header-search width 100% height 44px background #FFF border-bottom $hr .search-box background: #f3f5f4; border-radius: 14px; height: 28px; overflow: hidden; position relative; top: 8px margin 0 10px a text-decoration none i position absolute top 5px left 10px color #999 font-size 18px font-weight bold span font-size 14px color #ccc position absolute left 36px line-height 28px </style>
將該組件引入Home.vue和Category.vue中vue-cli
/* Home.vue */ <template> <div class="home"> <header-search/> </div> </template> <script> import HeaderSearch from '../../components/HeaderSearch/HeaderSearch' export default { name: 'home', components: { HeaderSearch } } </script> /* Category.vue */ <template> <div class="category"> <header-search/> </div> </template> <script> import HeaderSearch from '../../components/HeaderSearch/HeaderSearch' export default { name: 'category', components: { HeaderSearch } } </script>
運行效果npm
路徑:src/components/Banner/Banner.vueapi
<template> <div class="banner" ref="bannerImg" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"> <ul class="banner-img" @transitionend="transitionend" :style="{width: 100*(bannerData.length+2)+'%',transform: 'translateX('+translateX+'px)'}" :class="{transform:!isMove}"> <li> <a :href="bannerData[bannerData.length-1].path"> <img :src="bannerData[bannerData.length-1].imgUrl"/> </a> </li> <li v-for="data in bannerData"> <a :href="data.path"> <img :src="data.imgUrl"/> </a> </li> <li> <a :href="bannerData[0].path"> <img :src="bannerData[0].imgUrl"/> </a> </li> </ul> <ul class="banner-bullet" :style="{'margin-left': -(16*this.bannerData.length)/2 + 'px'}"> <li v-for="(data,i) in bannerData" :class="{on:i === bulletIndex }"></li> </ul> </div> </template> <script> export default { name: 'home', props: ['banner-data'], /* {imgUrl:'',path:''} */ data () { return { width: 0, index: 1, /* 0~bannerData.length + 1 */ translateX: '0px', isMove: true, bannerTouch: { startX: 0, endX: 0, distanceX: 0 }, timer: {}, timerData: 3000 /* 不能小於或等於過渡時間200秒 */ } }, mounted () { let p = this this.width = this.$refs.bannerImg.clientWidth this.translateX = -this.width this.timer = setInterval(function () { p.isMove = false p.index++ p.translateX = -p.index * p.width }, this.timerData) }, computed: { bulletIndex () { if (this.index >= this.bannerData.length + 1) { return 0 } else if (this.index <= 0) { return this.bannerData.length - 1 } return this.index - 1 } }, methods: { touchstart (ev) { this.bannerTouch.startX = ev.touches[0].clientX }, touchmove (ev) { clearInterval(this.timer) var move = ev.touches[0].clientX this.bannerTouch.distanceX = move - this.bannerTouch.startX this.translateX = -this.index * this.width + this.bannerTouch.distanceX this.isMove = true }, touchend (ev) { if (Math.abs(this.bannerTouch.distanceX) < this.width / 3) { } else if (this.bannerTouch.distanceX > 0) { this.index-- // = this.bannerData.length // 切換到倒數2 } else { // if (this.index >= this.bannerData.length + 1) { this.index++ } this.translateX = -this.index * this.width this.isMove = false let p = this clearInterval(this.timer) this.timer = setInterval(function () { p.isMove = false p.index++ p.translateX = -p.index * p.width }, this.timerData) }, transitionend () { if (this.index >= this.bannerData.length + 1) { this.index = 1 this.isMove = true this.translateX = -this.index * this.width } else if (this.index <= 0) { this.index = this.bannerData.length this.isMove = true this.translateX = -this.index * this.width } } } } </script> <style lang="stylus" rel="stylesheet/stylus"> .banner width 100% height auto overflow-x hidden position relative .banner-img display flex &.transform transition all .2s li flex 1 a display block img width 100% display block border none .banner-bullet position absolute bottom 15px; z-index 101 display flex left 50% li &.on:before background #bc0000 box-shadow 0px 0px 3px #bc0000 li:before content '' width 6px height 6px border-radius 3px border 1px solid #FFF display block margin 0px 4px box-shadow 0px 0px 3px #ccc </style>
修改Home.vue,引入該組件
<template> <div class="home"> <header-search/> <banner :banner-data="bannerData"/> </div> </template> <script> import HeaderSearch from '../../components/HeaderSearch/HeaderSearch' import Banner from '../../components/Banner/Banner' export default { name: 'home', components: { Banner, HeaderSearch }, data () { return { bannerData: [ { imgUrl: 'http://upload.shopncdemo.com/image/d5/3d/d53d507063c5195c74f24aabd9a0ec8a.jpg', path: '/100' }, { imgUrl: 'http://upload.shopncdemo.com/image/06/48/064879ea8043a03787ec849c10fa4400.jpg', path: '/2' }, { imgUrl: 'http://upload.shopncdemo.com/image/fb/c6/fbc658c0075ef4743e8cf0dd484a3796.jpg', path: '/3' }, { imgUrl: 'http://upload.shopncdemo.com/image/24/65/24656dd4e23f398abb9afc2543b8f8de.jpg', path: '/4' } ] } } } </script>
運行效果: