結局:vue-loader@13.X 降級到 vue-loader@12.X 便可解決
⭐️ 🌟 ✨ ⚡️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,一邊我又想拿到組件給個人回調,一邊又想本身加入參數,因此就須要這樣寫了:
7六、ElementUI 組件在 非.vue文件的使用,譬如router.js 文件中
import { Message } from 'element-ui'; Message('這是一條信息 );
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代碼,你應該懂得了
而且渲染在模板上
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 等方法。徹底不能夠監聽,應該說監聽很困難,常常出錯。事實上應該使用onTransitionEnd、onTransitionStart
當動畫完成時觸發:
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只能用於表單控件上,好比input、textarea、radio好比input、textarea、 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中,能夠自動監聽 firstName 和 lastName,當它們兩個變化的時候,自動會執行 fullName 這個函數,而後更新view層
若是你使用$watch的話,還須要同時編寫對 firstName 和 lastName 的回調函數
<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 賦值的路徑問題
可是某些狀況下咱們須要動態寫上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克隆一個對象
十二、組件生命週期鉤子的使用,必須是這種寫法:
經常使用的是mounted、created、
// 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
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>