基礎知識:vue-cli項目搭建及配置

vue-cli腳手架下載啓動

腳手架搭建css

// 安裝node、npm
    // 查看node版本
    node -v 
    
    // 查看npm版本
    npm -v
    
    // 如未安裝請安裝node, node會一塊兒安裝npm
    
// 全局安裝 vue-cli
    npm install vue-cli -g
     
// 下載腳手架項目 
    vue init webpack my-project
    
// 進入項目根目錄 
    cd my-project
     
// 啓動服務 
    npm start 或 npm run dev
    
// 訪問url 
    localhost:8080 或 127.0.0.1:8080

補充:
點這裏 → node下載地址html

主體結構說明vue

├─build                       // webpack配置文件(如:路徑配置、css預編譯等)
├─config                      // vue配置文件(如:端口、打包輸出等)
├─dist                        // npm run dev打包後的文件夾
├─node_modules                // node安裝依賴包
├─src                         // 資源文件夾
    ├─assets                  // 靜態文件資源
    ├─components              // 組件文件夾(如:common公用組件、pages頁面組件)
    ├─router                  // 路由文件夾
    ├─App.vue                 // vue入口文件
    ├─main.js                 // 頁面程序入口文件
├─static                      // 靜態資源(如:圖片、json數據等) 
├─.babelrc                    // es6解析的配置
├─.editorconfig               // 編輯器統一代碼風格的配置
├─.gitignore                  // git忽略提交的配置
├─.postcssrc.js               // css轉換的配置
├─index.html                  // 頁面入口
├─package-lock.json           // node_modules 或 package.json 發生變化時自動生成的文件
├─package.json                // 項目基本信息
└─README.md                   // 項目說明

// config
├─config 
    ├─dev.env.js              // 開發環境配置
    ├─index.js                // 主配置
    ├─prod.env.js             // 生產環境配置

// build
├─build 
    ├─build.js                // npm run build構建生產版本
    ├─check-versions.js       // 檢測node和npm的版本,實現版本依賴
    ├─utils.js                // css預編譯處理工具
    ├─vue-loader.conf.js      // vue處理工具(template、script、style)
    ├─webpack.base.conf.js    // 開發和生產共同使用的配置文件,主要實現配製入口,配置輸出環境,配置模塊resolve和插件等
    ├─webpack.dev.conf.js     // 開發環境webpack配置
    ├─webpack.prod.conf.js    // 生產環境webpack配置

config/index.js

端口node

// 更改端口
port: 3000,

打開瀏覽器webpack

// 是否在編譯完成後,自動打開瀏覽器訪問http://localhost:3000
autoOpenBrowser: false,

代理ios

proxyTable: {
  // 接口跨域
  // 解決跨域的問題
  '/lots-web/**': {
    target: 'http://localhost:8080' // 接口的域名
  },
  // 開發環境本地數據掛載 
  // json數據文件路徑:static/mock/index.json
  '/api': {
    target: 'http://localhost:7000',
    pathRewrite: {
    '^/api': '/static/mock'
    }
  }
}

build/webpack.base.conf.js

路徑配置git

alias: {
  'vue$': 'vue/dist/vue.esm.js',
  '@': resolve('src'),
  // import 'css/common.css'
  'css': resolve('src/assets/css')
}

build/utils.js

variables.scss預編譯es6

// 安裝模塊:
// npm install --save-dev sass-loader
// npm install --save-dev node-sass
// npm install --save-dev sass-resources-loader
scss: generateLoaders('sass').concat(
  {
    loader: 'sass-resources-loader',
    options: {
      resources: path.resolve(__dirname, '../src/assets/css/variables.scss')
    }
  }
)

// 使用方式:xxx.vue
@import 'css/xxx.scss'
<style lang='scss' scoped><style>

variables.styl預編譯web

// 安裝模塊:
// npm install --save-dev stylus
// npm install --save-dev stylus-loader
const stylusOptions = {
  import: [
    path.join(__dirname, "../src/assets/css/variables.styl")
  ]
}
return {
  stylus: generateLoaders('stylus', stylusOptions),
  styl: generateLoaders('stylus', stylusOptions)
}

// 使用方式:xxx.vue
@import 'css/xxx.styl'
<style lang='stylus' scoped><style>

src/main.js

初始 主文件vue-router

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false 

new Vue({
  el: '#app',
  router,
  components: {App},
  template: ''
})

詳細 主文件

// 入口 
import router from './router'                     // 路由
import store from './store'                       // 狀態
import api from './utility/api'                   // 接口
 
// 模塊 
import axios from 'axios'                         // 接口調用
import 'babel-polyfill'                           // ie9和一些低版本的瀏覽器對es6新語法的不支持問題
import fastClick from 'fastclick'                 // 延遲300毫秒
import VueAwesomeSwiper from 'vue-awesome-swiper' // 圖片輪播
import BScroll from 'better-scroll'               // 拖動插件
 
// 公用樣式 
import 'css/reset.css'                            // 重置
import 'css/common.css'                           // 公共
import 'css/border.css'                           // 1像素邊
import 'css/iconfont.css'                         // 文字圖標
import 'swiper/dist/css/swiper.css'               // 圖片輪播

// 公用組件 
import Fade from '@/pages/common/fade'            // 顯隱過渡
import Gallery from '@/pages/common/gallery'      // 畫廊
Vue.component('c-fade', Fade)
Vue.component('c-gallery', Gallery)
 
// 全局調用 
Vue.use(VueAwesomeSwiper)                         
Vue.prototype.$scroll = BScroll
Vue.prototype.$http = axios
Vue.prototype.$api = api

fastClick.attach(document.body)                   // 爲消除移動端瀏覽器,從物理觸摸到觸發點擊事件之間的300ms延時的問題

Vue.config.productionTip = false                  // 設置爲 false 以阻止 vue 在啓動時生成生產提示 

// 建立Vue 
new Vue({
  el: '#app',
  router,
  store,
  components: {App},
  template: '<App/>'
})

src/App.vue

vue入口文件
keep-alive數據緩存

<keep-alive :exclude="exclude">
  <router-view/>
</keep-alive>
data(){
  return {
    exclude: [
      'Detail'
    ]
  }
}

用法

// 一、如不填,則緩存所有組件
// 二、keep-alive include="City",緩存name='City'的組件
// 三、keep-alive exclude="Detail",不緩存name='Detail'的組件

生命週期

// 當時用keep-alive的時候,會觸發activated和deactivated生命週期
// activated 當組件被激活的時候調用
// deactivated 當組件被移除的時候調用

src/router/index.js

路由文件人口
初始 文件

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/home'

export default new Router({
  routes: [
    {
      path: '/home',
      component: Home
    }
  ]
)}

詳細 文件

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/home'

const path = {
  home: '/'
}

const router = new Router({

  // 路由和組件渲染 
  routes: [
    {
      path: path.home,
      component: Home
    }
  ],
  
  // 路由"#"號去除 
  mode: 'history',
  
  // 當前路由添加.active
  linkActiveClass: 'active',
  linkExactActiveClass: 'active',
  
  // 切換路由時界面始終顯示頂部 
  scrollBehavior(to, from, savePosition){
    return {
      x: 0,
      y: 0
    }
  } 
  
)}

export default router

src/store/index.js

狀態管理文件入口:index.js

// 狀態管理 
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'

Vue.use(Vuex)
export default new Vuex.Store({
  state,
  mutations,
  actions
})

第一步 引入state.js

// state.js 
let defaultCity = {
  id: 1,
  spell: 'beijing',
  name: '北京'
}
if(localStorage.city){
  defaultCity = JSON.parse(localStorage.city) // 字符串轉對象
}
const state = {
  city: defaultCity
}
export default state

第二步 引入mutations.js

// mutations.js 
const mutations = {
  changeCity(state, payload){
    state.city = payload
    localStorage.city = JSON.stringify(payload) // 當爲對象是,要轉字符串
  }
}
export default mutations

第三步 引入actions.js

// actions.js 
const actions = {
  changeCity(context, payload){
    context.commit('changeCity', payload)
  }
}
export default actions

第四步 vue文件使用vuex

// xxx.vue 
// template部分:
<div @click="handleClick(item)">{{city}}</div>

// script部分:
import { mapState, mapActions} from 'vuex'
export default {
  computed: {
    ...mapState(['city'])
  },
  methods: {
    ...mapActions(['changeCity'])
    handleClick(city){}
      this.changeCity(city)
    }
  }
}

axios

$http調用接口
全局調用

// 修改main.js文件
Vue.prototype.$http = axios
// xxx.vue文件:
this.$http
    .get('/api/index.json', {
      params: {...}
    })
    .then(
      fn(data)
    ).catch(
      fn(data
    ));

局部調用

// xxx.vue文件:
import axios from 'axios'
axios.get('/api/index.json')
     .then(
       fn(data)
     )
     .catch(
       fn(data)
     );

示例

getHomeData() {
  this.$http
    .get(this.$api.home, {
      params: {
        name: this.city.name
      }
    })
    .then(res => {
      let resData = res.data;
      if (resData.ret && resData.data) {
        let data = resData.data
        this.bannerList = data.bannerList
        this.iconList = data.iconList
        this.likeList = data.recommendList
        this.weekendList = data.weekendList
      }
    })
    .catch((err) => {
      console.log(err)
    })
}

移動端

縮放比例

// 修改文件:index.html
<meta minimum-scale=1.0, maximum-scale=1.0, user-scalable=no>
<meta width="device-width,
            height=device-height,
            initial-scale=1.0,
            minimum-scale=1.0,
            maximum-scale=1.0,
            user-scalable=no">

移動端初始配置

// 移動端訪問 
// 修改package.json文件:--host 0.0.0.0
// mac查看ip: ifconfig
// windows查看ip: ipconfig
// 手機訪問地址: ip地址:7000

初始化

// 初始化樣式 reset.css 
// 1px像素設備不一致 borer.css 
import 'css/common.css'                           // 公共
import 'css/border.css'                           // 1像素邊

延遲300ms

// 模塊 fastclick 解決移動端事件延遲300ms 
// main.js文件加入:
import fastClick from 'fastclick'                 // 延遲300毫秒
fastClick.attach(document.body)

iconfont

文字圖標

// 網址 http://www.iconfont.cn  
// 步驟 
// 選擇圖標加入購物車 →
// 添加到項目 →
// 下載到本地 →
// 字體和css複製到項目 →
// 更改iconfont目錄和刪除代碼 →

// 引入iconfont.css →
<span class="iconfont user-icon">&#x e624;><span>

better-scroll

拖動使界面滾動
全局

// 修改main.js文件:
import BScroll from 'better-scroll'
Vue.prototype.$scroll= BScroll
xxx.vue文件:
mounted() {
  this.scroll = new this.$scroll(elevent); // element爲dom或$refs
},

局部

// xxx.vue文件:
import BScroll from 'better-scroll'
this.scrolll = new BScroll(this.$refs.wrapper)
// 定位到某個元素 this.scroll.scrollToElement(element)

vue-awesome-swiper

圖片輪播

// 網址 https://www.swiper.com.cn/ 
// 步驟 
// 安裝模塊 vue-awesome-swiper 輪播插件(2.6.7)

// 修改main.js:
import "swiper/dist/css/swiper.css"
Vue.use(VueAwesomeSwiper)
xxx.vue文件:

<swiper :options="swiperOption" v-if="hasBanner">
  <swiper-slide v-for="item in list">
    <img :src="item.imgUrl">
  </swiper-slide>
  <div class="swiper-pagination" slot="pagination"></div>
</swiper>

swiperOption: {
  pagination: '.swiper-pagination',
  autoplay: 3000,
  paginationType: 'fraction',
  loop: true
}

router-link

路由連接

// router-link組件的active設置 
// 全局設置:
export default new VueRouter({
  linkActiveClass: 'active',
  linkExactActiveClass: 'active',
  routes : [
    ... 省略
  ]
});

// 局部設置:
<router-link :to="'home'" tag="li" active-class="active" exact-active-class="active" exact><標題router-link>
// 加上exact 則遵循路由徹底一致模式,該路由下的路徑不匹配 
// 標準 <router-link :to="'/detail?name=' + item.name" tag="div"></router-link> 
// 路由跳轉 this.$router.push('/')、this.$router.replace('/')

fade

過渡動畫

// template 
<transition>
  <slot></slot>
</transition>
 
// style 
<style lang="stylus" scoped>
.v-enter, .v-leave-to
  opacity 0
.v-enter-active, .v-leave-active
  transition opacity .5s
</style>

// name 
name="fade"
.fade-enter

touch

拖動事件

// touchstart/touchmove 
<div
  class="letter"
  @click="handleClickLetter"
  @touchstart.prevent="handleTouchStart"
  @touchmove="handleTouchMove"
  ref="letter">
  <div class="letter-cont" ref="letterCont">
    <span
      class="letter-item"
      v-for="item in list"
      :key="item">{{item}}</span>
  </div>
</div>
methods: {
  handleClickLetter(e) {
    const letter = e.target.innerHTML
    this.$emit('change', letter)
  },
  handleTouchStart() {
    this.letterHeight = this.$refs.letterCont.clientHeight / this.letterLen
    this.letterOffsetTop = this.$refs.letter.offsetTop + this.$refs.letterCont.offsetTop
  },
  handleTouchMove(e) {
    let touchY = e.touches[0].clientY
    let letterScope = (touchY - this.letterOffsetTop) / this.letterHeight
    if (letterScope > 0 && letterScope < this.letterLen) {
      if (this.timer) clearTimeout(this.timer)
        this.timer = setTimeout(() => {
        this.letterIndex = Math.floor(letterScope)
      }, 16)
    }
  }
}

其餘

組件裏name的做用

// 一、遞歸組件會用到
// 二、取消緩存的時候會用到
// 三、瀏覽器vue插件顯示組件的時候用到

子父組件傳值

// 子組件:
handleClick(){
  this.$emit('change', value)
}

// 父組件:
<component @change="handleClick"></component>
handleClick(){}

$refs

// this.$refs.msg 普通元素,引用指向dom:
<div ref='msg'>Hello, world<div>

// this.$refs.child 組件,引用指向組件實例:
<c-child ref='child'>Hello, world<c-child>

$route獲取url數據

// 1. /detail/:id
// /detail/1389435894
this.$route.params.id

// 2. /detail
// /detail?id=1389435894
this.route.query.id

利用setTimeout節流

if(this.timer) clearTimeout(timer);
this.timer = setTimeout(()=>{
  console.log(''xxx')
}, 16);

滾動監聽

// 1.
window.onscroll = this.handleScroll
// 2.
window.addEventListener('scroll', this.handleScroll)

瀏覽器cookie

localStorage.city = city
localStorage.clear()
相關文章
相關標籤/搜索