vue.js 的學習

⭐️ 🌟 ✨ ⚡️javascript

技術棧php

# vue官網
http://vuejs.org/

# Vuex中文手冊 
http://vuex.vuejs.org

#  Vue-Router 手冊 
http://router.vuejs.org 

# 最全Vue資源大全
https://github.com/opendigg/awesome-github-vue

# vue-devtool 調試vue必備chrome工具
https://github.com/vuejs/vue-devtools

# vue + typescript
https://github.com/HerringtonDarkholme/vue-ts-loader

# webpack2 中文文檔
http://www.css88.com/doc/webpack2/guides/code-splitting-require/

# Vuejs 實用技巧
https://zhuanlan.zhihu.com/p/25589193

# Vue.js 實用技巧(二)
https://zhuanlan.zhihu.com/p/25623356

# 餓了麼基於Vue 2.0的通用組件庫開發之路
https://mp.weixin.qq.com/s?__biz=MzIwNjQwMzUwMQ==&mid=2247484467&idx=1&sn=8643c5945adb151db9c6fe757cd6adfa&chksm=972366f1a054efe733e01069b2adb81d453a2c30bbc5329c77948e8160090294bf14918381a1&scene=21#wechat_redirect

 

⭐️ 🌟 ✨ ⚡️ Vue最好的UI庫css

# PC端
http://element.eleme.io/

# 移動端

https://github.com/ElemeFE/mint-ui

 

第三方插件收集:html

# vue-lazyload 一個簡單易用的 Vue 圖片延遲加載插件
https://github.com/hilongjw/vue-lazyload?from=gold
# 表單驗證插件
https://github.com/QingWei-Li/vuerify

# 前端國際化
https://github.com/kazupon/vue-i18n

# swpier強大且使人羨慕的拖拽組件
https://github.com/surmon-china/vue-awesome-swiper

 

安裝前端

注意 :因爲部分模塊是須要跨域才能下載,因此這裏須要使用cnpm install,cnpm是淘寶版本的npm,須要另外下載:http://www.cnblogs.com/CyLee/p/5719929.htmlvue

# 全局安裝 vue-cli
$ npm install -g vue-cli
# 建立一個基於 "webpack" 模板的新項目,注意,Use ESLint to lint your code? (Y/n) n $ vue init webpack my-project
# 安裝依賴,走你 $ cd my-project
# 使用cnpm進行安裝 $ cnpm install
# 運行,而且自動進入熱編譯 $ npm run dev

  端口能夠在config/index.js 中修改java

 咱們啓動頁看到的文件源代碼是:src/App.vuenode

 在build/webpack.base.conf.js 中搜索 jsLint 關鍵詞註釋掉相關的代碼便可關閉 jsLint 代碼嚴格模式react

 Vuejs不兼容低版本瀏覽器,好比IE八、360瀏覽器兼容模式等 jquery

 

 


  

神坑與碎片化知識點記錄

 

8六、watch route 沒法生效的緣由?

多是由於父子路由的緣由吧。建議用如下幾個方案代替:

watch: {
  '$route': {
      deep: true,
      handler (newV, oldV) {
          this.$store.dispatch('Map/reset')
      }
  }
},

2、若是仍是不行的話,用路由鉤子:

beforeRouteEnter (to, from, next) {
    next(vm => {
      if (from.path === '/myBusiness') vm.$router.push('/')
      next()
    })
}

// 頁面離開的時候,初始化一些參數配置
beforeRouteLeave  (to, from, next) {
    // 還原爲所有選擇框都顯示
    this.$store.dispatch('list/onlyShowSelect')
    // 取消問題類型,默認爲空
    this.$store.dispatch('list/eq_problemType')
    next();
},

 

 

 

8五、vue編譯插件,能夠發佈給人使用

$ vue-cli-service build --target lib --name w-basic-layout --dest lib packages/index.js

"scripts": {
  "lib": "vue-cli-service build --target lib --name w-basic-layout --dest lib packages/index.js"
},

 

 

8四、vuex 若是要dispatch另外一個模塊的actions時怎麼辦? 只須要加入 {root: true} 便可

dispatch('Map/fuck', 'shit', {root: true})

 

 

8三、vue 關於deep watch / computed 監聽不到 vuex state 對象變化的的問題

// 超簡易拷貝(若是是深拷貝還畫蛇添足把get/set拷貝進去了,因此用簡易拷貝便可)
let __VALUE__ = JSON.parse(JSON.stringify(state.problemReply))
// 加入部門回覆詳情
__VALUE__[orderId] = data.problemReply
// 更新,只能這樣一波騷操做才能讓computed和watch監聽到。具體緣由我稍後學習o(╥﹏╥)o。
state.problemReply = __VALUE__

 

8二、 如何在index.html加載本地js文件?

將文件放置在 /static 中 ,編譯的時候會一同打包在dist/static/ 中,因此你就能夠在index.html中使用

<script src="./static/echarts.min.js"></script>

 

8一、深度做用選擇器:https://vue-loader-v14.vuejs.org/zh-cn/features/scoped-css.html

vue組件會爲template中的每一個html元素加入 [data-v-xxxx] 屬性來確保 css 做用本組件而不會污染全局,而若是你引用了第三方組件,默認只會對組件的最外層(div)加入這個屬性,但第二層開始就沒有效果了。如圖所示: 第一層還有 data-v-17bb9a05, 但第二層的 .weui-cells 就沒有了。

若是你但願經過以下方式修改 weui-cells。是沒有效果的

<style scoped>
    .fuck .weui-cells {
        // ...
    }
</style>

除非你將scoped移出。或者新建一個沒有scoped的style(一個.vue文件容許多個style)。這是由於,全部的scoped中的css最終編譯出來都會變成這樣:

.fuck[data-v-17bb9a05] .weui-cells[data-v-17bb9a05]

解決方法還有另外一個,那就是深度做用選擇器:

 

重要的事情說三遍,若是你是scss之類的預編譯css的話, >>> 要換成 /deep/

重要的事情說三遍,若是你是scss之類的預編譯css的話, >>> 要換成 /deep/

重要的事情說三遍,若是你是scss之類的預編譯css的話, >>> 要換成 /deep/

 

80、mapState的使用。其中 theme 是模塊名。固然也能夠忽略。

import { mapState } from 'vuex'

computed: {
    ...mapState('theme', ['findLastSixMonthAir', 'findLastSixMonthAirTown'])
},

 

7九、computed + watch + vuex的組合,雖然一時爽,但也有問題,就是數據嵌套的太深的時候,沒辦法更新UI。又不能夠用$set方案來解決。

但也有辦法,那就是深拷貝賦值,而後在某一層賦值,仍是能夠更新UI的。

// 超簡易拷貝(若是是深拷貝還畫蛇添足把get/set拷貝進去了,因此用簡易拷貝便可)
const v = JSON.parse(JSON.stringify(state.list.data))
// 加入回覆字段
v[index].problemReply = data.problemReply
// 更新,只能監聽到data屬性,因此必須這樣操做。不能這樣:  state.list.data[index].problemReply = data.problemReply
state.list.data = v

 

 

 

7八、因爲一些嵌套特別深的數據,致使數據更新了。UI沒有更新,我捉摸着有沒有和react同樣的當即更新UI的API呢 this.forceUpdate()呢?結果還真有:

this.$forceUpdate();

 

7七、使用<el-select>時使用它的事件@change,一邊我又想拿到組件給個人回調,一邊又想本身加入參數,因此就須要這樣寫了:

 

 @change="(data) => childCheckbox(data,index, item)" 

 

 

7六、ElementUI 組件在 非.vue文件的使用,譬如router.js 文件中

import { Message  } from 'element-ui';

Message('這是一條信息 );

 

 

7五、props如何雙向屬性綁定

 

 

7四、vue 中使用scoped關鍵字後樣式不能修改第三方組件問題

https://blog.csdn.net/mr_hexs/article/details/80375244 

 

7三、vue動畫的使用。

https://cn.vuejs.org/v2/guide/transitions.html

.cell-enter-active, .cell-leave-active {
  transition: all 1s;
}

/* 新成員進入時的動畫 */ .cell
-enter, .cell-leave-to /* .cell-leave-active below version 2.1.8 */ { /*opacity: 0;*/ transform: translateY(300px); } /* 全部項移動時的動畫鉤子 */ .cell-move { transition: transform 1s ease; } <transition-group name="cell" tag="div" class="transition-group"> <div v-for='(item, index) in items' :key='item' class="cell"> {{ item.title }} </div> </transition-group>

 

 

7二、史詩級的神坑:v-for循環中,我習慣這樣使用index:v-for='(item, index) in items' :key='index'

當我對items數組的前面插入數據時:

this.items.unshift({title: '重大事件', time: '2018.08.08 10:00', content: '渦領商業西街食物中毒', num: '1'})

因爲加入了transition-group 動畫,我能夠很清楚的看見插入的動畫效果,卻一直是push的效果。後來查看官方demo,才發現這個:key須要這樣設置:

v-for='(item, index) in items' :key='item'

 

7一、v-cloak 用來解決渲染以前的尷尬期

https://segmentfault.com/a/1190000008819667

 

70、vue v-model 與 組件化的表單組件如何溝通

參考mint-ui的代碼:

https://github.com/ElemeFE/mint-ui/blob/master/packages/radio/src/radio.vue

https://github.com/ElemeFE/mint-ui/blob/master/packages/field/src/field.vue

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
    <style>
    </style>

    <body>
        <div id="app">
            <div v-for='(item, index) in items' :key='index'>
                <myradio v-model="picked" :text="item"></myradio>
            </div>
            <br>
            <span>Picked: {{ picked }}</span>
        </div>
    </body>
    <script>
        // 局部註冊組件
        var myradio = Vue.extend({
              data: function () {
                    return {
                        currentValue: this.value
                    }
              }, 
              props: {
                value: '',
                text: ''
              },     
              template: `
                <label>
                    <input type="radio" id="two" :value="text" v-model="currentValue">
                    <label for="two">{{ text }}</label>
                </label>
              `,
              watch: {
                    value(val) {
                      this.currentValue = val;
                    },
                    currentValue(val) {
                      this.$emit('input', val);
                    }
              }
        });

        Vue.component('myradio', myradio)

        new Vue({
            el: '#app',
            data: {
                picked: 'Three',
                items: ['One', 'Two', 'Three']
            }
        })
    </script>

</html>

 

 

 

 

6九、input 聚焦的時候鍵盤蓋住

function getElementTop(element){
    try {
      var actualTop = element.offsetTop;
      var current = element.offsetParent;
      while (current !== null){
        actualTop += current.offsetTop;
        current = current.offsetParent;
      }
      return actualTop;
    } catch (e) {}
    }

setTimeout(() => {
    window.scrollTo(0, getElementTop(e.target));
}, 150)

 

 

 

 

6八、註冊全局指令

https://cn.vuejs.org/v2/guide/custom-directive.html

// v-auth 全局權限指令,但暫時沒有想好怎麼處理
Vue.directive('auth', {
  inserted: function (el, node) {
    // 從 store 中獲取權限信息
    var auth = store.state.auth.authInfo
    // 遍歷權限列表
    for (var i = 0; i < auth.length; i++) {
        // 若是符合條件,那麼就把它刪除
        if (auth[i].resContent === node.value) {
            // 刪除元素
            return el.parentNode.removeChild(el)
        }
    }
  }
})

 

 

 

6七、新的錯誤出現:Module build failed: Error: No parser and no file path given, couldn't infer a parser.

https://segmentfault.com/q/1010000015052538

運行:npm i prettier@~1.12.0

 

6六、Vue自帶的錯誤捕獲機制

https://cn.vuejs.org/v2/api/#errorHandler

Vue.js 2.2.0+提供了 errorHandler, (通常在src目錄的main.js文件中配置) 

Vue.config.errorHandler = function(err, vm, info) {
    console.log(err, vm, info);
};

  

 6五、fetch中response.json()的問題

一、你不能連續使用兩次response.json(),不然會報錯

二、你不能直接在promise中打印出console.log(response.json()),打印不出的。因此你必須這樣

var json = response.json()
json.then(_=>{ console.log(_) })
return json

 

 

6四、webpack-dev-server 沒法經過ip訪問的問題

http://www.cnblogs.com/CyLee/p/8376648.html

 

6三、路由的限制和next的問題。 

 if (needLoginPage.indexOf(to.fullPath.replace(/\/|\\/g, '').toLocaleLowerCase().trim()) >= 0 && !store.state.token) {
        // 史詩級神坑,這裏必須先next,不然會一直返回不了,
        // 不要問我爲何,我猜想是,因爲你缺乏了一次next,一直卡着不給後退。因此這裏不管如何也須要next一下.
        Toast('請先登陸')

        // next()
        // 設置去路
        return store.dispatch('set_wantTo', to.path).then(_ => {
            // 跳轉到登陸頁
            router.push('/login')
            // 繼續渲染它?
            return next()
        })
}

 

 

 

 

6二、分享一個小技巧,若是項目遷移、而node_modules遷移有問題,項目啓動不了的時候,能夠選擇徹底刪除node_modules。而後重點來了

不要使用window內置的powser shell,而是使用一些高亮的shell工具如cmder。執行cnpm install試試。若是仍是不行,繼續重複刪掉node_modules,反覆執行cnpm install。記得要用cmder哦

 

6一、學完局部註冊和全局註冊的差異後,你再看看main.js的new Vue代碼,你應該懂得了

 

這是由於:你的入口main.js中,僅僅註冊了一個全局組件App.vue,

 

而且渲染在模板上

綁定在html上的一個叫#app的元素上

也就是說,你的全部組件,都是在App.vue下活動的子組件。



而子組件的切換,是經過url來切換的?如何切換呢?是經過路由來監聽切換的


基本上就是這樣的原理

 

60、Vue warn]: Do not use built-in or reserved HTML elements as component id: button

將組件的name屬性從button改成mybutton便可。

export default {
    name: 'mybutton',
    // ...
}   

 

 

5九、webpack 使用別名(resolve.alias)解決scss @import相對路徑致使的問題

 

5八、vue 更新了vue-cli到最新版本後引起的問題: require和import、vue-loader的問題

結局:vue-loader@13.X 降級到 vue-loader@12.X 便可解決

 

5七、手動掛載$mount()

若是沒有掛載的話,沒有關聯的 DOM 元素。是獲取不到$el的。

https://vuejs.org/v2/api/#vm-mount

var MyComponent = Vue.extend({
  template: '<div>Hello!</div>'
})

// create and mount to #app (will replace #app)
new MyComponent().$mount('#app')

// the above is the same as:
new MyComponent({ el: '#app' })

// or, render off-document and append afterwards:
var component = new MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)

 

5六、銷燬組件

// get~ 銷燬組件
destroyElement() {
  this.$destroy(true);
  this.$el.parentNode.removeChild(this.$el);
},

 

5五、vue.extend 局部註冊 的應用2

請注意,extend建立的是一個組件構造器,而不是一個具體的組件實例。因此他不能直接在new Vue中這樣使用: new Vue({components: fuck})

最終仍是要經過Vue.components註冊纔可使用的。 

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>在Vue中註冊組件</title>
</head>
<body>
<div id="app">
    <todo :todo-data="groceryList"></todo>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue " type="text/javascript"></script>
<script>
/**
 * 請注意,extend建立的是一個組件構造器,而不是一個具體的組件實例。
 * 因此他不能直接在new Vue中這樣使用: new Vue({components: fuck})
 * 最終仍是要經過Vue.components註冊纔可使用的。 
 */

// 構建一個子組件
var todoItem = Vue.extend({
    template: ` <li> {{ text }} </li> `,
    props: {
        text: {
            type: String,
            default: ''
        }
    }
})

// 構建一個父組件
var todoWarp = Vue.extend({
    template: `
        <ul>
            <todo-item 
                v-for="(item, index) in todoData"
                v-text="item.text"
            ></todo-item>
        </ul>
    `,
    props: {
      todoData: {
          type: Array,
          default: []
      }
    },
    // 局部註冊子組件
    components: {
        todoItem: todoItem
    }
})

// 註冊到全局
Vue.component('todo', todoWarp)

new Vue({
    el: '#app',
    data: {
        groceryList: [
            { id: 0, text: '蔬菜' },
            { id: 1, text: '奶酪' },
            { id: 2, text: '隨便其它什麼人吃的東西' }
        ]
    }
})
</script>
</html>

 

5四、vue.extend 局部註冊 的應用1

請注意,在實例化extends組件構造器時,傳入屬性必須是propsData、而不是props哦

另外,不管是Vue.extend仍是Vue.component 裏面的data定義都必須是函數返回對象,如 Vue.extend({data: function () {return {}}})。除了new Vue能夠直接對data設置對象以外吧,如 new Vue({data: {}});

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>在Vue中註冊組件</title>
</head>
<body>
<div id="todoItem"></div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue" type="text/javascript"></script>
<script>

// 局部註冊組件
var todoItem = Vue.extend({
  data: function () {
        return {
            todoData: [
              { id: 0, text: '蔬菜' },
              { id: 1, text: '奶酪' },
              { id: 2, text: '隨便其它什麼人吃的東西' }
            ]
        }
  },
  template: `
        <ul>
            <li v-for='(d, i) in todoData' :key="i">
                {{ d.text }}
            </li>
        </ul>
  `
});

// 請注意,在實例化extends組件構造器時,傳入屬性必須是propsData、而不是props哦
new todoItem({
  propsData: {
      todoData: [
          { id: 0, text: '蔬菜' },
          { id: 1, text: '奶酪' },
          { id: 2, text: '隨便其它什麼人吃的東西' }
      ]
  }
}).$mount('#todoItem')

</script>
</html>

 

5三、Vue的實例屬性

 

5二、歷來沒使用過 <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script> 的使用方式。

一直都是工程化來開發的。如今也開始使用一下吧。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
    <script src="./Components/Counter.js"></script>
</head>
<body>
    <div id="app">
        <p>總數量: {{ total }}</p>
        <counter @add="handleGetTotal" @reduce="handleGetTotal"></counter>
    </div>
</body>
<script>
    new Vue({
        el: '#app',
        data: {
            total: 0
        },
        methods: {
            handleGetTotal: function (v) {
                this.total = v;
            }
        }
    })
</script>
</html>

 

Components/Counter.js

Vue.component('counter', {
        template: `
            <div>
                <button type="button" @click="handleAddNum">+</button>
                <button type="button" @click="handleReduceNum">-</button>
            </div>
        `,
        data: function () {
            return {
                counter: 0
            }
        },
        methods: {
            handleAddNum: function (){
                this.counter++;
                this.$emit('add', this.counter);
            },
            handleReduceNum: function (){
                this.counter--;
                this.$emit('reduce', this.counter);
            }
        }
})

 

 

 

5一、enter事件,常常用但常常忘記。仍是記錄一下把 

@keyup.enter="enterHandle"

 

50、簡單的知識點,如何調用子組件的函數Methods

答案就是使用ref便可。

<countdown  ref="countdown"></countdown>

beforeDestroy () {
      // 切換頁面時消滅計時器
      this.$refs.countdown.clearTimer()
}

 

4九、使用vue-cli 配置 proxyTable 代理地址,實現跨域問題

路徑在/config/index.js 中,找到dev.proxyTable。以下配置示例:

    proxyTable: {
        '/api': {
            // 我要請求的地址
            target: 'http://oatest.bujidele.com:8010/apitest/api/tydproject/doOld/',  
            //是否跨域 
            changeOrigin: true, 
            // 重寫地址 
            pathRewrite: {
              '^/api': '/'
            }
        }
    }

 那麼當咱們請求 http://localhost:8888/api/ 的時候,就等於請求了 http://oatest.bujidele.com:8010/apitest/api/tydproject/doOld/

請注意上面的【pathRewrite】字段。這是什麼意思呢。

咱們再來看看下面的例子

 proxyTable: {
        '/api': {
           // 我要請求的地址
           target: 'http://192.168.14.29:31006/xindai/',  
           //是否跨域 
           changeOrigin: true, 
           // 重寫地址 
           pathRewrite: {
             '^/api': '/api'
           }
       }
  },

若是是這樣的話,當咱們請求/api的時候,就等於請求了http://192.168.14.29:31006/xindai/api

這要看你要不要了,若是不要的話,直接換爲'^/api': '/' 就行了

 

4八、獲取組件本身在父組件中的索引。

內置屬性便可。this.index 。 

隨便一提這些內置的屬性應該多記一點,譬如this.$parent.xxxx 這些都是很實用的

 

4七、經過js新建組件而且傳入props: 

import Vue from 'vue';
import product from './index.vue';

let productComponent = Vue.extend(product);

export default (food, isShow, idx, ratings) => {
    new productComponent({
        el: '#goodss',
        propsData: {
            food,
            isShow,
            idx,
            ratings
        }
    });
}

 

4六、axios 加入header以後,請求出現

Failed to load http://localhost:8080/team.php: Request header field x-jwt-header is not allowed by Access-Control-Allow-Headers in preflight response.

//POST傳參序列化(添加請求攔截器)
axios.interceptors.request.use(config => {
    config.headers['x-jwt-header'] = localStorage.token
    return config;
},error =>{
    alert("錯誤的傳參", 'fail')
    return Promise.reject(error)
})

緣由是後端沒有開啓對header的容許。php中輸入如下代碼便可:

header('Access-Control-Allow-Headers:x-jwt-header,content-type'); 

 

4五、webpack 打包壓縮 ES6文件報錯UglifyJs + Unexpected token punc (();  或者 Unexpected token: operator (>) 

解決方案就是將babel配置轉義到 .babelrc 文件中。具體作法是在根目錄新建 .babel,輸入

{
    "presets": ["es2015"]
}

在webpack加載babel-loader的時候會自動加載.babelrc配置的。

 

4四、若是不能看到源碼來修復bug真心累。除非是經過場景重現的bug。不然定位不到錯誤行很慘。因此須要開啓map。

在 /config/index.js 中,修改 productionSourceMap 爲 true 便可。

 

4三、儘管加入了babel-polyfill ,依然出現 【ReferenceError: Promise is not define】的問題。目前只在三星、金立手機出現這種問題。沒辦法,只能強行修復了。

npm install promise --save-dev

window.Promise = require('promise');

記得清除一下手機的緩存。

 

4二、記一塊兒和前端沒什麼卵關係的後端405問題

問題的關鍵點在於原本是POST請求,會變成OPTION請求,而且提示405報錯,會相似跨域。而且只有某些手機機型纔會(如Oppo系列)。

其實跨域的問題,若是在PHP只須要在頭設置容許跨域便可。其餘語言也相似。 

header("Access-Control-Allow-Origin:*");
或者
header("Access-Control-Allow-Origin:url地址");

 但.net聽說也設置大體如上設置了,卻不能輕易跨域,在開發環境中我甚至須要開啓代理或瀏覽器非安全模式才能夠跨域。

直到今天這個問題在線上完全爆發出來。才認真研究。其緣由就在於.net web.conf配置中,須要註釋或刪除這一句配置:

<remove name="OPTIONSVerbHandler" />

因而具體配置大體以下:

<handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <!--<remove name="OPTIONSVerbHandler" />-->
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>

    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
      </customHeaders>
    </httpProtocol>

問題便可解決。不管線上和本地均可以順利跨域了。其實就是個跨域的問題罷了,記錄一下

 

4一、記一次餓了麼UI圖標加載無效的問題。而且提示錯誤

Failed to decode downloaded font:

很顯然,問題在於webpack的loader中。檢查了一下發現有兩個相同的file-loader的配置,刪除其中一個便可。

 

40、記一次編譯沒反應、無進度、沒有任何報錯的提示,但後臺卻TM一直消耗內存的BUG:

控制檯一直提示「building for production...」,並且spinner中止了動畫!

因爲沒有任何的提示。何況項目的代碼、結構、設計徹底未知模糊的狀況下,我只能按照unix的理念「使之運行、使之正確、使之快速」做爲理論依據指導我來調試了。

按照這個理念,我最初設定的目標,就是讓他正常的編譯,不管結果是如何。因此我將main.js(入口文件)的代碼儘量刪掉。只保存純潔無比的app.vue組件。以及vue的初始化。就這樣運行編譯,果真可行!!然後我經過按照二分法。一步一步還原並刪減一半的代碼,運行npm run build。一步一步嘗試。直到定位到最小單元的文件(result.vue),在這個文件中只有三個劍客,分別是template、script、css。他們同樣沒有逃過個人魔爪,一步步的刪減,直到最後定位到了是css文件的錯誤。一個css文件竟然能引起這種史詩級的錯誤?經過繼續對css文件中的css代碼進行二分法刪減,最後發現。怎麼會有一個「|」符號?因而把它刪除,正常編譯!

結果和過程都是美好的。但我以爲我這種調試方式也值得記錄。

 

3九、組件 vue-awesome-swiper 的坑

一、在vertical的場景模式下,默認的高度很奇怪,很是很是的大。徹底沒有規律。後來使用autoHeight好了一點。但依然有問題,問題在於它會根據swiper-slide內元素的高度自動變化疊加。依然會很是很是大。最後才知道。手動設置height便可解決。因爲個人場景是fullpage頁面,因此只須要設置height : window.innerHeight 便可。完整代碼以下:

swiperOption: {
          direction : 'vertical',
          height : window.innerHeight,
          onTransitionStart: function (swiper){
                this.isHideIcon = swiper.activeIndex <= 3;
          }.bind(this)
}

 

二、在拖拽的過程當中,我還發現另外一個bug。有時候拖拽邊緣。會致使沒有很好的彈性滾動,而是像普通頁面同樣滑動致使錯誤了。後來檢查才發現,是由於你手勢滑動的區域不是<swiper>元素覆蓋的範圍致使的。解決方案很簡單,整個頁面都讓swiper覆蓋便可。保證用戶觸碰的是swiper元素自己,而不是body、或者其餘div元素

 

3九、默認Vue-cli腳手架的工程,npm run build以後的工程是必須部署在服務器根目錄中的,只能用相似localhost:8080/#/來訪問。緣由是資源的路徑讀取都是以根目錄'/',因此咱們只須要修改靜態資源的路徑便可。打開工程目錄中

/config/index.js

找到build屬性中的assetsPublicPath,默認是「/」 修改成"./"便可

 

 

3八、Error: [vuex] vuex requires a Promise polyfill in this browser. 與 babel-polyfill 的問題

事實上以前已經解決了。採用最笨重的解決方案就是npm install babel-polyfill 而後在webpack中如此設置:

entry: {
  'babel-polyfill': 'babel-polyfill',
  app: './src/main.js'
},

但在開發環境下,咱們在IE11打開的時候依然有問題(但在現代瀏覽器中瀏覽竟然沒問題)。打開源碼,能夠看到是app.js先加載,而後才加載babel-polyfill. 其實在生產環境下(webpack編譯以後)。能夠正常運行。這是由於在webpack.prod.conf.js中的HtmlWebpackPlugin加入了 hunksSortMode: 'dependency' 屬性。因此咱們只要依樣畫葫蘆。在webpack.dev.conf.js中找到HtmlWebpackPlugin加入了 hunksSortMode: 'dependency' 屬性便可

 

3七、(深度更新)好吧,其實36的理解是錯誤的,雖然解決了問題。但對於this.$set的理解是大錯特錯的。關鍵在於對vue的雙向數據綁定太信賴而致使無視了原理。

https://segmentfault.com/a/1190000007787941?_ea=1459649

事實上,回憶一下咱們在使用Vue的雙向數據綁定的時候,咱們首先須要在Data中配置屬性,而後再綁定到template中。而後改變Data時,就會改變template。

但有沒有經歷過我這種狀況,默認的Data的某個屬性是空的,如 list: {}  我須要進行異步請求或者延遲操做以後,再給它賦值 list.fuck = 'fuck-Vue' 若是是這樣的狀況。你以爲template會更新麼。

答案是否認的。這其實很是容易猜測到緣由。Vue默認只會綁定Data中的數據,而你異步更新的Data。實質上只是更新了,但並無綁定,因此template天然沒有更新。那有沒有解決方案呢?

有的。36的this.$set就是解決方案,它的做用是,添加綁定一個狀態而且馬上更新template。也就是說,拿個人例子作說明,默認list: {} 當賦值的時候再也不是單純的this.list.fuck = 'fuck-Vue'; 而是 this.$set(this.list, 'fuck', 'fuck-vue');

這樣便可解決,但須要注意一個問題: this.$set 不能添加或更新已有的屬性,不然無效。什麼意思呢?好比個人Data的list中,默認已經寫有fuck這個屬性了。若是你繼續使用 this.$set(this.list, 'fuck', 'fuck-vue'); 則是無效的。

3六、史詩級的知識點以及解決方案:一個複雜對象的變化,vue是不能監聽到的,因此視圖也不會隨着改變?怎麼辦?

好比我有一個狀態:

[

    {toggle: true, rotate: true},

    {toggle: false, rotate: false},

    {toggle: false, rotate: false}

]

固然這個狀態是經過api獲取的。經過v-for渲染後,當我改變數組中其中一個對象的一個屬性時:

this.Model[index].rotate= !this.Model[index].rotate

對象確實有改變,但視圖不會更新。爲何? 詳情閱讀:https://cn.vuejs.org/v2/guide/reactivity.html

總之你只要知道,默認Vue是不能檢測屬性更新來刷新視圖的。只有this.$set的方法來解決:https://cn.vuejs.org/v2/api/#Vue-set 

methods: {
    slideupList (index) {
        this.Model[index].rotate= !this.Model[index].rotate
        this.Model[index].toggle = !this.Model[index].toggle
        
        /**
         * 因爲this.Model是對象數組,當其中一個對象變化的時候,vue不能監聽到的,因此視圖也不會刷新
         * this.$set 這個方法主要用於避開  Vue 不能檢測屬性更新的限制。
         * 但這個方法的使用須要注意幾點:
         * - 我是對數組中的某個值(這個值是個對象),直接從新賦值的。
         * 若是我這裏直接對數組的某個對象中的某個屬性賦值,那是不行的。
         * https://cn.vuejs.org/v2/api/#Vue-set
         * http://www.cnblogs.com/zhuzhenwei918/p/6893496.html
         * */
        this.$set(this.Model, index, this.Model[index])
    }
}

  

3五、如何監聽Vuex的state?  經過Computed + watch的組合 

 computed: {
          get_translateY() {
            return this.$store.state.translateY;
          }
        },
        watch: {
          get_translateY (val) {
             window.clearTimeout(this.Timer);
             this.isHeadAdd = true;
             this.hide = window.setTimeout(() => {
                 this.isHeadAdd = false;
             }, 1000)
          }
        }

  

3四、vue-router的keep-alive緩存策略

 - keep-alive 是 Vue 內置的一個組件,可使被包含的組件保留狀態,或避免從新渲染。 

# 第三方手冊
http://www.jianshu.com/p/0b0222954483

# 官方手冊
https://vuejs.org/v2/api/#keep-alive

注意include不能有空格,如

  <keep-alive include="carBusiness,houseBusiness">
    <router-view class="view"></router-view>
  </keep-alive>

  

3三、vuex中mapState的概念是什麼?有點懵逼???

其實就是重命名而已,爲了能夠減小你輸入的鍵盤,詳細能夠看看這篇博客:

http://blog.csdn.net/a641832648/article/details/62233213

 

3二、就憑這個坑,我相信typescript會替換babel

Cannot set property requestCount of #<Object> which has only a getter

場景這樣的:使用了多個export + import * as xxx 組合,但屬性只讀 

# state.js // 異步請求的數量
export let fetchCount = 0
// translateX的監聽器
export let translateX = 0
// translateY的監聽器
export let translateY = 0
# index.js import * as state from './state.js' console.log(state) // 你會發現這些屬性只有getter沒有seter。說明是隻讀的

緣由是babel的配置中  .babelrc的presets屬性中存在{ "modules": false }。移除就行了。

 

3一、Vuejs的動畫API更新換代了N次。不得不說我愈來愈欣賞和熟悉了。這要歸功於完美用戶體驗的API手冊。

下面這個demo是演示 animate.css 與 自定義transition 和 vuejs的API結合 

<template>
   <div id="app">
           <transition name="fuck">
             <div class="div" v-if='isShow'> </div>
          </transition>
          <button v-on:click="isShow = !isShow"> Toggle </button>
  </div>
</template>

<script>  
export default {
  name: 'app',
  data () {
    return {
      isShow: true
    }
  }
}
</script>

<style lang="scss" scoped>
  .div {
    height: 200px;
    width: 200px;
    background: red;
  }

  .fuck-enter-active{
     animation-duration: 1s;
     animation-fill-mode: both;
     animation-name: fuck;
  }

  .fuck-leave-to {
    opacity: 0
  }

  .fuck-leave-active {
     transition: opacity .5s
  }

  @keyframes fuck{
        from {
          opacity: 0;
          transform: translate3d(0, 100%, 0);
        }
        to {
          opacity: 1;
          transform: none;
        }
  }
</style>

 

30、可使用@input 代替 watch

因爲@input自己就是用來監聽表單控件(input/select/radio等)的值變化,而且在@input事件的回調中,他的執行是比v-model被賦值快的,依賴這個特性能夠代替watch的效果

<input v-model="test_model" @input="test" type='text' />

test (e) {
   // 你會發現不同v-model此時還沒賦值
   console.log(this.test_model, e.target.value)
}

 

2九、深度監聽 deep watch

當使用watch時,若是要監聽的是一個對象或者一個數組。默認是監聽不了的。須要開啓deep

http://cn.vuejs.org/v2/api/#watch

http://www.cnblogs.com/hity-tt/p/6677753.html

data () {
    return {
        // 表單數據集   
        formModel: {
            // 借款類型
            borrow_type: '',
            // 借款金額
            borrow_money: '',
            // 業務狀態
            status: '',
            // 備註
            remark: ''
        }
    }        
},
watch: {
  formModel: {
    handler (newValue, oldValue) {
    console.log(newValue)
  },
    deep: true
  }
}

 

2八、安卓和IOS時間轉換和顯示的兼容性問題,統一解決

// 時間補0輔助函數
const padNumber = (num, fill) => {
    //改自:http://blog.csdn.net/aimingoo/article/details/4492592
    var len = ('' + num).length;
    return (Array(
        fill > len ? fill - len + 1 || 0 : 0
    ).join(0) + num);
}

// 轉化時間格式爲年月日
const timeYMD = time => {
    // 若是傳入非法參數,直接返回空
    if (isNullOrEmpty(time)) return null
    // 兼容安卓的噁心狀況 2017-05-2021:53:13 或 2017-04-1000:00:00 替換爲: 2017-05-20 21:53:13
    if (/(-|\/){1}(\d{4})/.test(time)) {
        // 獲取中點
        const mid = time.lastIndexOf('-') + 3
        // 生成正確的時間字符串
        time = time.substr(0, mid) + ' ' + time.substr(mid)
    }
    // 兼容IOS和安卓
    var d = new Date(Date.parse(time.replace(/-/g, "/")))    
    // 若是轉換成功
    if (d != 'Invalid Date') {
        time = d.getFullYear() + "-" + padNumber(d.getMonth() + 1, 2) + "-" + padNumber(d.getDate(), 2) + ' '
        // 若是時都不爲0的時候,才疊加上
        if (d.getHours()) { 
            time += d.getHours() + ':'
             // 若是時分秒都不爲0的時候,才疊加上
            time += padNumber(d.getMinutes(), 2) + ':'
             // 若是時分秒都不爲0的時候,才疊加上
            time += padNumber(d.getSeconds(), 2)
        }
        // 返回轉換成功後的值
        return time
    }
    // 不然返回轉換失敗的標記
    return 'Invalid Date'
}

 

2七、必須掌握的技巧:webpack 與 路由 —— 代碼分割

https://router.vuejs.org/zh-cn/advanced/lazy-loading.html

http://www.css88.com/doc/webpack2/guides/code-splitting-require/

# API地址:http://www.css88.com/doc/webpack2/guides/code-splitting-require/ # webpack 在編譯時,會靜態地解析代碼中的 require.ensure(),同時將模塊添加到一個分開的 chunk 當中。這個新的 chunk 會被 webpack 經過 jsonp 來按需加載。

# router.js const Home = r => require.ensure([], () => r(require('../views/Home.vue')), 'Home')

# vue-cli腳手架中/build/webpack.prod.conf.js,output修改成如下樣子:
output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[name].[chunkhash].js')
 }

 

2六、組件單元測試所須要的知識點: 

# ./my-component.js
export default { 
  template: '<span>{{ fuck }}</span>',
  props: ['fuck'],
  created () {
    console.log('created')
  }
}


# main.js // 製做組件
Vue.component('MyComponent', Object.assign(MyComponent, {
    data () {
        return {
            fuck : 'you'
        }
    },
    beforeMount () {
        console.log("beforeMount")
    }
}));

// 新建組件 使用new Vue({//...}) 或者 Vue.extend({ //... }) 均可以
const HtmlContainer = Vue.extend({
  data () {
    return {
      text: '喵了個咪'
    }
  }, 
  template: `<my-component :fuck='text'></my-component>`
})

// 組件須要掛載,有兩種方式
// 方式1:
const vm = new HtmlContainer({
   el: document.createElement('div'),
})
// 方式2:
const vm = new HtmlContainer().$mount(document.createElement('div'))

// 打印來看看結果吧:
console.log(vm, vm.$el, vm.$el.textContent)

  

2五、路由可選參數的坑: 

# 若是該參數是動態的數值,直接加入‘?’便可
/houseBusinessDetails/:id?

# 但若是是固定的數值,則須要加入()?才能夠
/houseBusinessDetails/(id)?/:id?

# 正則表達式加可選參數
/myBusiness/:tag([0-2]?)

 

2四、低端機的es6/7兼容性問題:[vuex] vuex requires a Promise polyfill in this browser.

Babel默認只轉換新的JavaScript句法(syntax),而不轉換新的API,好比Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局對象,以及一些定義在全局對象上的方法(好比Object.assign)都不會轉碼。

舉例來講,ES6在Array對象上新增了Array.from方法。Babel就不會轉碼這個方法。若是想讓這個方法運行,必須使用babel-polyfill,爲當前環境提供一個墊片。

知乎關於babel-runtime的問題:https://www.zhihu.com/question/34854349

阮一峯的babel和es6相關文章:http://www.ruanyifeng.com/blog/2016/01/babel.html 

# 安裝
npm install --save-dev babel-polyfill

# webpack
entry: {
    'babel-polyfill': 'babel-polyfill',
    app: './src/main.js'
}

Babel默認不轉碼的API很是多,詳細清單能夠查看babel-plugin-transform-runtime模塊的definitions.js文件。

這樣一來就可使用全部的es6/7特性了。該方案能夠說是對方案【14】的無腦版。無腦引入全部的特性。很是冗餘但沒辦法的時候能夠用

 

2三、經常使用的組件內的路由鉤子

beforeRouteEnter (to, from, next) {
    next(vm => {
      if (from.path === '/myBusiness') vm.$router.push('/')
      next()
    })
}

 

2二、從vuex、store的一個使用細節感覺到vuejs的開發哲學:

我一直覺得store的依賴vue的。直到有一次,意外的先執行了store中自定義的action,而後再初始化new vue({store})。卻依然正常無誤後才理解。緣由store打從一開始就不須要依賴vue,它之因此須要加入到vue,只是爲了能夠在vue的生命週期中,方便使用this來調用它僅此而已。store徹底能夠單獨使用。從這點能夠看出,vue的插件系統和設計很是的優秀

 

2一、fastclick的bug以及解決方案: 當點擊select的時候,瀏覽器會渲染出源生的列表,這時候,表單極可能向上拖拉。這時候,鼠標會繼續滲透,極可能恰好點擊到拖拉後的input上。而後會呼出鍵盤,取消掉select。解決方案以下:

 

20、史詩毀滅宇宙級別的坑:webpack1 版本的 autoprefixer 沒法在build編譯後生效,只在開發模式下生效,緣由是webpack.optimize.UglifyJsPlugin 插件的影響,註釋掉便可

 

 1九、使用new Date()的一點兼容性小坑

# 並非全部的瀏覽器都支持如下轉換語法
let data = new Date('2017-04-30 16:47:09')

# 但都支持這種轉換方法
let data = new Date('2017/04/30 16:47:09')

# 因此儘量要對 ‘-’ 進行替換
var date = new Date(this.model.Model.claimDate.replace(/-/g, '/'));

 

1八、放置冒泡和鼠標穿透最簡單的方法:@click.stop 

 <button v-if="_isEditable" class="btn btn-white" @click.stop="goToEdit(data.business_id,data.approve_id,data.flow_business_type,data.after_id)">編 輯</button>

 

 1七、過濾器的正確用法和常規用法

無代碼演示,直接使用computed便可。聰明的你確定知道怎麼作了。

隨便找的一個例子:https://blog.csdn.net/sinat_17775997/article/details/56495373

簡單示例:

<input type="text" v-model="search_content">
<ul class='list__items'>
    <li v-for='(item, index) in filterItems' :key='index' @click='handleClick(item.schoolId)'>
        {{ item.schoolName }}
    </li>
</ul>
data: {
    search_content: '',
    // 學校列表
    items: []
},
computed: {
   filterItems: function () {
       var self = this;
       return self.items.filter(function (item) {
           return ~item.schoolName.indexOf(self.search_content.trim())
       })
   }
},

 

 

 

1六、v-html 渲染html的內容 

<section class="notice-body" v-html="myData['notice_content']">

  

1五、$nextTick + Mounted 解決對未渲染的dom的進行操做報錯的問題

methods: {
    changeSwiperAction () {
       this.$nextTick(() => {
          for (let [index, elem] of this.swpierList.entries()) {
             if( elem.title === this.swiperAction ) return this.$refs.swiperRef.swiper.slideTo(index, 300, false)
          }
       })
    }
 },
mounted () {
   this.changeSwiperAction()
}

 

-1四、es2016/es6/es7以上的js儘管有babel編譯,或者什麼babel的plugin的transform-runtime也沒什麼用。當你使用了新特性的時候,依然不會進行轉換,依然須要修補匠babel-polyfill

但請按需引入,缺什麼就補什麼:https://github.com/zloirock/core-js

或者使用npm install --save-dev babel-polyfill安裝,而後在node_modules中查找core-js文件夾也能夠

 

// 按需加載Es修補匠
require('./modules/es7.object.entries')
require('./modules/es6.array.iterator');

 

-1三、同一個坑我踩了兩次:雙向數據綁定 

我清空兩個數組的數據,爲了簡潔這樣寫: 

this.messageList = this.businessList = []

但這樣一來,根據vuejs的特性,這兩個list就綁定上了。數據就會同步了……(mmp),因此改成這樣就行了……(cnm)

// 清空數據
this.messageList = []
this.businessList = []

 

-十二、組件 vue-awesome-swiper 的坑

監聽切換事件,但若是使用 onSlideChangeStart、onSlideChangeEnd、onSlideNextStart、onSlidePrevStart 等方法。徹底不能夠監聽,應該說監聽很困難,常常出錯。事實上應該使用onTransitionEndonTransitionStart

當動畫完成時觸發:

 swiperOption: {
          pagination: '.swiper-pagination',
          paginationClickable: true,
          nextButton: '.swiper-button-next',
          prevButton: '.swiper-button-prev',
          spaceBetween: 30,
          effect: 'coverflow',
         onTransitionStart: function (swiper) { this.drawMap.index = swiper.activeIndex }.bind(this)
      }

 

-十一、主動更新組件上的model

當咱們開發了一個子組件,而且給某個地方的父組件調用了。此時,若是父組件在子組件上綁定了一個V-model。父組件但願子組件的某些狀態變化時,能夠順便更新一下這個v-model的值。那麼問題來了。子組件獲取和更新這個未知的v-model呢?

# 獲取v-model
console.log(this.value); // 對,就是這麼簡單

# 更新組件上的v-model值. 只須要調用input事件便可,參數爲更新的值
fuckXXOO (v) {
  this.$emit('input', v);
}

  

-十、 屬性函數傳參的尷尬

若是要爲組件綁定一個click事件,可使用@click="fuck($event)"。 這是正常的。

但若是是自定義組件,你的@click可能會無效。這時咱們想能夠傳遞一個函數進去,讓組件自己@click處理。那好,我傳遞一個屬性:clickMethod="fuck('123')"。那麼就不正常了。由於該函數fuck('123')會當即執行。根據這個特性,正確的解決方案是這樣的:(返回一個函數)

# template
:clickMethod="MenuListClick(item.title,index,item.path)" # script
MenuListClick (title,index,to) {
    return function () {
       console.log(title,index,to)   
    }    
}

 

 

-九、雙向數據 與 組件,以自定義select組件爲例。原理很簡單,子組件使用$emit來調用綁定在函數組件上的函數,而且傳參。而綁定在組件上的函數是在父組件中運行的。拿到參數後父組件就能夠隨心所欲了

# 子組件中的模板 <select class="mint-field-core" v-if="type === 'select'" @change="$emit('fuck', currentValue)" v-model="currentValue">
<option v-for="(o,index) in option" :value='o.value'>{{ o.text }}</option>
</select> # 子組件中的屬性和狀態
data() {
    return {
        currentValue: this.value
    };
},
props: {
    option: {
        type:Array
    },
    value: {}
}



# 父組件中使用子組件:


# template模板 <mt-field label="業務類型" placeholder="請選擇業務類型" type='select' :option="list" :value="currSelect" @fuck="handleChange"></mt-field> # data狀態
list:[
    {"value":"1","text":"車易貸1"},
    {"value":"2","text":"車易貸2"},
    {"value":"3","text":"車易貸3"},
    {"value":"4","text":"車易貸4"}
],
currSelect:"1" # methods方法
handleChange (val) {
    console.log("handleChange",val);
    this.currSelect = val
}

 

-8、v-model的新姿式:任何組件均可以使用

之前覺得只有表單控件才能夠擁有v-model的權利和意義,
事實上任何元素/組件(包括自定義組件),均可以使用v-model。
好比說我定義了一個<lee-select>選擇框組件,我但願往該組件中傳入一個v-model,而且用它遍歷出來的值生產option。那麼我能夠這樣作:

# template
<lee-select v-model="list"> # script
data () {
    return {
      list:[
        {"id":"1","text":"車易貸1"},
        {"id":"2","text":"車易貸2"},
        {"id":"3","text":"車易貸3"},
        {"id":"4","text":"車易貸4"}
      ]
    }
 }

那麼我在lee-select組件的內部如何獲取該v-model而且循環呢?事實上,系統內置了一個狀態:【value】
代碼以下:

<option v-for="v in value" value='v'>{{ v.text }}</option>

這樣一來,就正常的獲取而且遍歷出來拉!!!

 

-7、$refs的簡單使用:獲取Dom對象

<div class="mint-loadmore-top" ref="loadImage"></div>

// 查看各類各樣的dom屬性
console.log(this.$refs.loadImage);

 

-六、watch的簡單彷佛用

data() {
      return {
         translate: 0      
      }
}
watch: {
  translate (curVal, oldVal) {
    this.Remtranslate = curVal / 75
  }

}  

 

-五、讓路由與狀態融合的插件:vuex-router-sync

import { sync } from 'vuex-router-sync'
import router from './router'
sync(store, router)

把 vue-router 的狀態放進 vuex 的 state 中,這樣就能夠透過改變 state 來進行路由的一些操做

import * as type from './mutation-types.js'

const mutations = {
    [type.IS_LOADING] (state, b) {
        console.log(state.route)  // 打印出路由的實例,那麼咱們就能夠經過它來改變路由地址,隨心所欲了
        state.is_loading = b;
    }
}

export default mutations;

 

 

-四、props 設置默認值和其餘配置 

  props: {
    show: {
      required: false,
      default: true
    }
  }

  

 

-三、 v-bind 和 v-model的區別

咱們知道二者的做用都是能夠實現數據的雙向綁定。

v-model只能用於表單控件上,好比inputtextarea、radio好比inputtextarea、 select/option等,而且主要是來獲取和操做表單控件的Value。

這樣區分的話,v-bind的做用就很明顯了。它能夠用來綁定任何屬性。好比class / id / placeholder ,甚至自定義屬性:fuck / shit 等。但請不要嘗試代替v-model的職能,好比綁定了input控件的value屬性。那麼顯然是無效的。還請用V-model綁定

 

 

-二、 npm run build 以後路徑的坑:

       默認的腳手架,編譯以後全部的靜態資源路徑是相對於/static。 事實上應該是./static  那應該如何改呢?

       打開腳手架目錄下 /config/index.js 文件。

       修改 build -> assetsPublicPath : "./" 便可

 

 

-一、神奇的computed,又叫屬性計算,其做用等於增強版的$watch。它的神奇之處在於能夠自動監聽函數中使用的狀態。以下demo中,能夠自動監聽 firstNamelastName,當它們兩個變化的時候,自動會執行 fullName 這個函數,而後更新view層

 若是你使用$watch的話,還須要同時編寫對 firstNamelastName 的回調函數

<div id="demo">{{fullName}}</div>

var vm = new Vue({
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

 

 

0、webpack編譯vue不經過的狀況(好比Cannot find modulee test.vue,可是能夠找到js文件,很明顯就是vue文件編譯失敗): 

# 檢查.babelrc 或 babel-loader 的配置,確保使用了stage-0以上的版本
npm install babel-preset-stage-2 --save-dev

  

  

一、<style>標籤中若是要使用sass,須要指定scss而不是sass,以下:<style lang="scss" scoped>,而且須要先安裝兩個模塊:

npm install node-sass sass-loader --save

這裏有個天坑。明明安裝了上述兩個插件,在編譯運行的時候依然會報相似的錯誤:

ERROR in ENOENT: no such file or directory, scandir 'C:\Users\Lee\Desktop\xindaiApp3\node_modules\node-sass\vendor'

解決方案是:打開node_modules,找到node_sass 和 sass-loader 兩個文件夾刪掉。而後使用cnpm install 從新安裝便可。若是仍是不行,直接刪除整個node_modules,而後執行cnpm install從新安裝

若是依然不行。那麼直接使用必殺技:安裝windows-build-tools.

# github地址
https://github.com/felixrieseberg/windows-build-tools

# 安裝命令(使用管理員運行powershell / cmd運行如下代碼)
npm install --global --production windows-build-tools

解決了我多年 node-sass 安裝失敗的問題.也包括之後的各類npm環境依賴問題

安裝完成以後,能夠經過 npm rebuild node-sass 來測試是否編譯正常。若是仍是不正常。那可能須要你手動安裝一下buildTool_Full.exe

大概目錄位置在 C:\Users\用戶名\.windows-build-tools\BuildTools_Full.exe. 若是你電腦上已經有VS系列,那可能須要先刪除,才能夠安裝了。具體本身想辦法解決

 

二、<style>標籤中若是要使用less,以下:<style lang="less" scoped> ,而且須要先安裝兩個模塊:

npm install less less-loader --save

 

 

 

三、Vue中的watch 很是容易使用,因此我沒有書寫任何的demo,但有一個點要注意,VueJs並非很是精準的監聽。好比說

我定義了一個data爲items = [];若是我對這個items直接賦值一個數據,watch就會監聽到,但若是items自己是一個複雜的object結構,好比說數組對象中的數組,當最內層的數組發生變化時,watch是不會監聽到的。

  

 

四、在 Vue 2.0 中,爲自定義組件綁定原生事件必須使用 .native 修飾符: 

 <my-component @click.native="handleClick">Click Me</my-component>

 

五、屬性賦值,一般是動態的model,但爲了方便也能夠直接賦值bool或者string以下:

:_left="false"     //布爾值

:_rightText="'貨幣轉換'"   //字符串

 

 

六、V-bind 三元表達式的問題 ,不可使用雙引號

其餘屬性表達式請查看手冊:http://vuejs.org/v2/api/#v-bind

:class="item.name == '我' ? 'odd' : 'even' "

 

 

七、Vuejs 變量拼接的問題。

# 方式1 字符串 + 變量
:href=" '#content' +  index"

# 方式2 變量 + 變量
<img :src="baseUrl + imgUrl">

 

 

八、vue.js+webpack 爲 img src 賦值的路徑問題 

若是靜態的寫上地址如:'./images/abc.png'。就會被webpack編譯爲loader 插件編譯成base64風格的地址。

可是某些狀況下咱們須要動態寫上src地址,但動態的地址又不會被編譯。怎麼辦呢?解決方案以下:

astroImage:require(`./images/${this.$route.params.consName}.png`) 

 

 

 

九、vue的template,若是html的屬性如src、class 想賦值一個data的話,就必須加上: 將其變成屬性如 :class="xxx"   :src="xxx"

 

   

 

十一、宇宙級深坑:

我新建了一個變量。把items賦值給他,而後我修改這個變量。items竟然也跟着修改了

解決方案是這樣修改:

var arr = this.items.slice(0); // 利用slice函數克隆一個數組
arr.push(10);  // 進行一些操做
console.log(this.items); // 不會被影響到 

接下來是對數組進行克隆,使用es6的語法

let new_obj = Object.assign({}, [your obj]);  // 利用Object.assign克隆一個對象

 

 

十二、組件生命週期鉤子的使用,必須是這種寫法:

經常使用的是mountedcreated

  // beforeCreate、created、beforeDestroy、destroyed、beforeMount、mounted、beforeUpdate、updated、activated、deactivated 

  beforeDestroy () {
    this.$parent.route_pipe(false);
  }

 

1三、組件名不能夠爲html內置的譬如說<footer><header>

 

 

1四、<tamplate>中的html最好在最外層包裹着一個<div>. 這很重要。而且直接影響路由的使用transition的使用

 

 

1六、路由使用  

  // 路由超連接   ,注意這個to,若是是純字符串的時候直接to="xxxx",若是是變量的時候再使用:to

 <router-link :to=backPath :class=backPath ></router-link> 

//加入全局變量,這樣才能在其餘地方調用
window.router = router

//跳轉
router.push("bar")

//可使用afterEach + vuex 來實現動態獲取後退頁面的地址
router.afterEach((to, from) => {
   console.log(to, from)
})

//可使用beforeEach 來攔截頁面  而且進行一些操做以後再放行next()
router.beforeEach((to,from,next) => {
  console.log(to,from);
  next(); //放行
})

//children子路由,當咱們在order頁面中加入 <router-view> 時,orderDetails 頁面 會從該 <router-view> 中進出
 {

      path:'/order',component:require('./views/order'),
  children:[
    {path:':id',component:require('./views/orderDetails')}
  ] 
 }  

 /*  再來一個子路由的demo: 

      上面的demo中,不知爲什麼?若是直接寫上:id ,會直接將子路由配置的頁面顯示在父頁面中。

       因此我換成這個demo的就能夠了。只有等我點擊纔出如今父頁面. */

 {path:'/astro',component:require('./views/astro/index'),children:[{path:'/astro/:consName',component:require('./views/astro/info')}]}

 

  // 監聽路由頁面進入事件

  beforeRouteEnter:(to, from, next) => {
    // 在渲染該組件的對應路由被 confirm 前調用
    // 不!能!獲取組件實例 `this`
    // 由於當鉤子執行前,組件實例還沒被建立
    next( vm => {
      vm.$parent.route_pipe(true);
    });
  },

  // 監聽路由頁面的退出事件  

  beforeRouteLeave (to, from, next) {
    console.log(this); 
    next(); 
  },

//若是兩個頁面都是經過同一個 <router-view> 進出,那麼他們的動畫事件(enter/leave)會同時觸發,儘管某些場景下能實現華麗的效果。
//但某些場景你不想被混淆,譬如層層嵌套的界面:index->order->orderDetails.相似這種頁面結構,應該使用嵌套路由 + chilren路由配置,參考上面的子路由demo 
View Code
 

 

 

20、css中的轉義符號 「\」  在編譯【npm run build】的時候可能不經過。須要刪修掉。這種狀況可能會出如今svg中,如圖

  

 

demo2: 循環

補充:在循環中可使用{{ $index }} 來獲取索引

vue2.0 在V-for中這樣書寫格式:v-for="(item,index) in items"  而後就能夠這樣使用了  :data-index="index"

<template>
  <div id="app">
     <h1>{{title}}</h1> <!-- <h1 v-text='title'></h1> -->
     <ul>
       <li v-for='item in items' v-bind:class="{finished: item.isFinished}"> {{item.label}} </li>
     </ul>
  </div>
</template>

<script> export default { data () { return { title: 'Hello World!', items: [ { label: 'coding', isFinished: false }, { label: 'walking', isFinished: true } ] } } } </script>

<style> .finished{text-decoration: underline;} html {height: 100%; } body {display: flex; align-items: center; justify-content: center; height: 100%; } #app {color: #2c3e50; margin-top: -100px; max-width: 600px; font-family: Source Sans Pro, Helvetica, sans-serif; text-align: center; } #app a {color: #42b983; text-decoration: none; } .logo {width: 100px; height: 100px }
</style>

 


 

 

demo2-1  bind屬性

v-bind指令能夠在其名稱後面帶一個參數,中間放一個冒號隔開,這個參數一般是HTML元素的特性(attribute),例如:v-bind:class

該指令一般綁定的是一個表達式、model、(也能夠是純字符串但沒什麼意義)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <link rel="stylesheet" href="styles/demo.css" />
    </head>
    <body>
        <div id="app">
            <ul class="pagination">
                <li v-for="n in pageCount">
                    <a href="javascripit:void(0)" v-bind:class="activeNumber === n + 1 ? 'active' : ''">{{ n + 1 }}</a>
                </li>
            </ul>
        </div>
    </body>
    <script src="js/vue.js"></script>
    <script>
        var vm = new Vue({ el: '#app', data: { activeNumber: 1, pageCount: 10 } }) </script>
</html>

 


 

 

demo3: 事件與雙向數據綁定

一、$event  訪問原來的 DOM event,你能夠傳遞一個 $event 參數進去: @click="change_title($event)"

而後能夠這樣調用

change_title (e) {
  console.log(e.target.innerText)

  //利用zepto/jquery訪問源生對象 

  console.log($(e.target).html())

} 

二、若是在手機模式下@click是無效的,須要使用@touchend或者@touchstart

<template>
  <div id="app">
     <h1>{{title}}</h1> <!-- <h1 v-text='title'></h1> -->
     <input type="text" v-model='newItem' @keyup.enter='addItem'>
     <ul>
       <li v-for='item in items' v-bind:class="{finished: item.isFinished}" v-on:click='toggleFinish(item)'> {{item.label}} </li>
     </ul>
  </div>
</template>

<script> export default { data () { return { title: 'Hello World!', items: [ { label: 'coding', isFinished: false }, { label: 'walking', isFinished: true } ], newItem: '' } }, methods: { toggleFinish (item) { item.isFinished = !item.isFinished }, addItem () { console.log(this.newItem) this.items.push({ label: this.newItem, isFinished: false }) this.newItem = '' } } } </script>

<style> .finished{text-decoration: underline;} html {height: 100%; } body {display: flex; align-items: center; justify-content: center; height: 100%; } #app {color: #2c3e50; margin-top: -100px; max-width: 600px; font-family: Source Sans Pro, Helvetica, sans-serif; text-align: center; } #app a {color: #42b983; text-decoration: none; } .logo {width: 100px; height: 100px }
</style>

 

 


 

demo5-1 微實戰

 

知識點:事件、數據綁定、循環

<template>
   <div id="app">
        <fieldset>
        <legend>Create New Person</legend>    
        <div class="form-group">
          <label>Name:</label>
          <input type="text" v-model="newPerson.name" />
        </div>
        <div class="form-group">
          <label>Age:</label>
          <input type="text" v-model="newPerson.age" />        
        </div>
        <div class="form-group">
          <label>Sex:</label>
           <select v-model="newPerson.sex">
             <option></option>
             <option></option>
           </select>
        </div>
        <div class="form-group">
            <label></label>
            <button @click="createPerson">Create</button>
        </div>
     </fieldset>
     <table>
       <thead>
         <tr>
            <th>Name</th> <th>Age</th> <th>Sex</th> <th>Delete</th>
         </tr>
       </thead>
       <tbody>        
         <tr v-for="p in people">
           <td>{{ p.name }}</td>
           <td>{{ p.age }}</td>
           <td>{{ p.sex }}</td>
           <td><button @click="deletePerson($index)">Delete</button></td>
         </tr>
       </tbody>
     </table>
   </div>
</template>
<script type="text/javascript"> export default { data () { return { newPerson : {name : '', age : 0, sex : ''}, people : [ {name: 'Jack', age: 30, sex: 'Male'}, {name: 'Bill', age: 26, sex: 'Male'}, {name: 'Tracy', age: 22, sex: 'Female'}, {name: 'Chris', age: 36, sex: 'Male'} ] } }, methods : { createPerson () { //添加到數組
          this.people.push(this.newPerson) //重置
          this.newPerson = {name : '', age : 0, sex: ''} }, deletePerson (index) { // 刪一個數組元素
          this.people.splice(index,1) } } } </script>
<style> * {margin: 0; padding: 0; box-sizing: border-box } html {font-size: 12px; font-family: Ubuntu, simHei, sans-serif; font-weight: 400 } body {font-size: 1rem } table, td, th {border-collapse: collapse; border-spacing: 0 } table {width: 100% } td, th {border: 1px solid #bcbcbc; padding: 5px 10px } th {background: #42b983; font-size: 1.2rem; font-weight: 400; color: #fff; cursor: pointer } tr:nth-of-type(odd) {background: #fff } tr:nth-of-type(even) {background: #eee } fieldset {border: 1px solid #BCBCBC; padding: 15px; } input {outline: none } input[type=text] {border: 1px solid #ccc; padding: .5rem .3rem; } input[type=text]:focus {border-color: #42b983; } button {outline: none; padding: 5px 8px; color: #fff; border: 1px solid #BCBCBC; border-radius: 3px; background-color: #009A61; cursor: pointer; } button:hover{opacity: 0.8; } #app {margin: 0 auto; max-width: 640px } .form-group {margin: 10px; } .form-group > label {display: inline-block; width: 10rem; text-align: right; } .form-group > input, .form-group > select {display: inline-block; height: 2.5rem; line-height: 2.5rem; } .text-center{text-align: center; } .pagination {display: inline-block; padding-left: 0; margin: 21px 0; border-radius: 3px; } .pagination > li {display: inline; } .pagination > li > a {position: relative; float: left; padding: 6px 12px; line-height: 1.5; text-decoration: none; color: #009a61; background-color: #fff; border: 1px solid #ddd; margin-left: -1px; list-style: none; } .pagination > li > a:hover {background-color: #eee; } .pagination .active {color: #fff; background-color: #009a61; border-left: none; border-right: none; } .pagination .active:hover {background: #009a61; cursor: default; } .pagination > li:first-child > a .p {border-bottom-left-radius: 3px; border-top-left-radius: 3px; } .pagination > li:last-child > a {border-bottom-right-radius: 3px; border-top-right-radius: 3px; }
</style>

 

 


 

 


 

 

demo5-3: 封裝常見的後臺左側菜單 

 

<template>
    <div>
        <input type="text" v-model='keyword' placeholder="全文搜索(未實現)" />
        <div v-for="(item,index) in items">
            <h1 @click="myfunc($event,index)">{{item.title}}</h1>    
            <!-- 隨便弄了一個動畫,不喜歡直接刪除transition標籤 -->
            <transition name="slide">
                <!-- 當數組中不存在當前索引時纔出現 -->
                <ul v-if = "closeIndex.indexOf(index) === -1">            
                    <li  v-for=" l in item.list " >
                        {{ l }} 
                    </li>
                </ul>                
            </transition>
        </div>
    </div>
</template>

<script>
    export default {
        data () {
            return {
                keyword : "",
                closeIndex : [],
                items:[
                    {title:"合同管理",list:["合同錄入","合同審覈"]},
                    {title:"結算單管理",list:["結算單錄入","結算單審覈","渠道異常管理"]},
                    {title:"基礎數據管理",list:["渠道信息管理","渠道折扣信息管理","用戶角色管理","管理配置頁面"]}

                ]
            }
        },
        methods:{
            myfunc (el,index) {
                var _index = this.closeIndex.indexOf(index);
                if(_index > -1)            
                   this.closeIndex.splice(_index,1);            
                else
                    this.closeIndex.push(index);                
            }
        }
    }
</script>

<style scoped>
    .slide-enter-active,.slide-leave-active {
      transition: all .35s ease;
    }
    .slide-enter,.slide-leave-active {
       opacity: 0;
       transform: translate3d(-100%,0,0);
    }   
    ul li{list-style: none}
    h1{font-size:16px;font-weight: normal;font-family: "微軟雅黑"}
</style>

 


 

 

 demo5-4:超級炫酷的洗牌

<template>
    <div>
      <button @click="shuffle"> Shuffle </button>
      <transition-group name="cell" tag="div" class="container">
        <div v-for="cell in cells" :key="cell.id" class="cell">
              {{ cell.number }}
        </div>
      </transition-group>
    </div>
</template>

<script>
    export default {
        data () {            
            return {
                 cells: Array.apply(null, { length: 81 }).map(function (_, index) { 
                      return {
                        id: index,
                        number: index % 9 + 1
                    }
                  })
            }
        },
        methods:{
             shuffle: function () {
                 var arr = this.cells.slice(0);     // 利用slice函數克隆一個數組.不要問我爲何要克隆
                 this.cells = this.myshuffle(arr);
             },
             /* ES6版本的洗牌函數 */
             myshuffle (arr) {
                   let n = arr.length, random;
                    while(0!=n){
                        random =  (Math.random() * n--) >>> 0; // 無符號右移位運算符向下取整
                        [arr[n], arr[random]] = [arr[random], arr[n]] // ES6的結構賦值實現變量互換
                    }
                    return arr;
             }
        }
    }
</script>

<style scoped>

/* 動畫鉤子 */
.cell-move {
  transition: transform 1s ease;
}

.container {
  display: flex;
  flex-wrap: wrap;  /* #當寬度不夠時換行 */
  width: 238px;
}

.cell {
  text-align: center;
  width: 25px;
  height: 25px;
  border: 1px solid #aaa;
}

</style>

 

 

Demo10 : vue-socket 

 

若是要在vue中使用socket,則須要第三方模塊:Vue-Socket.io  

https://github.com/MetinSeylan/Vue-Socket.io

 

server服務端,神坑:必須讓sendClientData中的代碼單獨抽離爲一個函數,否則只有發起server_menu事件的客戶端才能收到。很奇怪

let socket = sio.listen(server);
socket.on('connection',function(socket){
    console.log("socket start!");
    socket.on("server_menu",function(menu_data){
        fs.writeFile('../data/desk.json',menu_data,function(err){
            if(err) console.error("文件寫入失敗");
            else console.log("文件寫入成功");
        });
        sendClientData(menu_data);
    })
})
let sendClientData = (data) => {
    socket.emit('client_menu',data);
}

client客戶端: 

import VueSocketio from 'vue-socket.io';
Vue.use(VueSocketio, 'http://localhost:8090');

 sockets : {
      connect : function(){
      console.log('socket connected')
    },
      client_menu : function(data){
          console.log("client_menu",data)
      }    
  }

 created () {
     this.$socket.emit("server_menu",{name:"test"});
  }

 

 

demo 11 : 全局插件 install 

 

# global.js
export default {
    install ( Vue ) {
        Vue.prototype.functions = {
      getVersion () { 
                return "1.0"
            }
    };
    }
}
 # main.js
import plugins from './../plugins/global.js';
Vue.use(plugins);

# navbar.vue
created () {
   alert(this.functions.getVersion());
}

 

 

demo12 : 插槽做爲組件使用

 

一、若是插槽沒有定義name屬性,那麼傳遞進來的全部【內容】都會插入其中;
二、若是插槽定義了name屬性,但外部的【內容】沒有指定solt的name,那麼沒法插入該插槽;
三、若是插槽定義了name屬性,而且外部的【內容】分別指定了solot的name屬性,那麼會對號入座插入對應的插槽中;

這裏的【內容】指的是文本、HTML元素、vue組件等等... 事實上並無很難理解。只須要試試如下的demo,而且嘗試更改solt相關的內容便可學會

# 子組件 tabbar.vue ——————————————————————————————————————————————————
<template>
    <div class="m-tabbar">
       <slot></slot>
    </div>
</template>
<style lang="less">
.m-tabbar{
    display: flex;
    flex-direction: row;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    overflow: hidden;
    height: 50px;
    background: #fff;
    border-top: 1px solid #e4e4e4;
}
</style>

# 子組件 tabbar-item.vue ———————————————————————————————————————
<template>
    <a class="m-tabbar-item" >
        <span class="m-tabbar-item-icon"><slot name="icon-normal"></slot></span>
        <span class="m-tabbar-item-text"><slot></slot></span>
    </a>
</template>

<style lang="less">
.m-tabbar-item{
    flex: 1;
    text-align: center;
    .m-tabbar-item-icon{
        display: block;
        padding-top: 2px;
        img{
            width: 28px;
            height: 28px;
        }

    }
    .m-tabbar-item-text{
        display: block;
        font-size: 10px;
        color:#949494;
    }
    &.is-active{
        .m-tabbar-item-text{
            color: #42bd56;
        }
    }
}
</style> # 父組件 index.vue ———————————————————————————————————————————— <template>
  <div>
    <m-tabbar>
      <m-tabbar-item id='tab1'>
        <img src="../assets/images/ic_tab_home_normal.png" alt="" slot="icon-normal"> 
        首頁
      </m-tabbar-item>
      <m-tabbar-item id='tab2'>
        <img src="../assets/images/ic_tab_subject_normal.png" alt="" slot="icon-normal"> 
        書影音
      </m-tabbar-item>
      <m-tabbar-item id='tab3'>
        <img src="../assets/images/ic_tab_status_normal.png" alt="" slot="icon-normal" /> 
        廣播
      </m-tabbar-item>
      <m-tabbar-item id='tab4'>
        <img src="../assets/images/ic_tab_status_normal.png" alt="" slot="icon-normal" /> 
        小組
      </m-tabbar-item>
       <m-tabbar-item id='tab5'>
        <img src="../assets/images/ic_tab_profile_normal.png" alt="" slot="icon-normal"> 
        個人
      </m-tabbar-item>
    </m-tabbar>
  </div>
</template>

<script>
  import mTabbar from '../components/tabbar'
  import mTabbarItem from '../components/tabbar-item'
  export default {
    name: 'index',
    components: {
      mTabbar,
      mTabbarItem
    }
  }
</script>

 

 

 

 

HTTP   [,eitʃti:ti:'pi:]   詳細 X
基本翻譯
abbr. 超文本傳輸協議(Hyper Text Transport Protocol)
網絡釋義
HTTP: 超文本傳輸協議(Hyper Text Transfer Protocol)
HTTP referer: HTTP參照位址
http Proxy: 代理服務器
相關文章
相關標籤/搜索