本文同步發佈到 http://www.kt5.cn/fe/2019/11/04/vue-qna/javascript
this.arr[index] = value; this.$set(this.arr, index, this.arr[index]); // vue監聽不到數組內的元素的值的變化,要手動通知觸發, 或者用compute來得出新的view數組進行處理,或者使用watch來監聽變化從新進行更新
this.$set(this.jsonObj, 'myKey', myValue); // 針對jsonObj
解決方案通常以下:php
vue監聽不到數組/json對象內的元素的值的變化,一、要手動通知觸發, 2、或者用compute來得出新的view數組/jsonObj進行處理,3、或者使用watch/deep watch來監聽變化從新進行更新 css
this.arr[i] = null // 能夠把元素設爲null,使用時用compute進行過濾便可 this.$set(this.arr, i, this.arr[i]) // this.arr.splice(i, 1) // 此方法有可能會致使視圖更新錯誤
可行方案:html
一、能夠把打包出來靜態文件中的index.html改爲.tpl或者.php尾的等模板文件格式,而後能夠在裏面動態輸出一些js變量如token,userinfo等信息供vue應用使用vue
二、也能夠初始化的內容經過接口來請求過來,保存在localstorage或者全局變量供全局使用java
this.$router.go(-1) // 後退 相似 window.history.go(n) // 字符串 router.push('/home') // 對象 router.push({ path: '/home' }) // 命名的路由 router.push({ name: 'user', params: { userId: 123 }}) // 帶查詢參數,變成 /register?plan=private router.push({ path: '/register', query: { plan: 'private' }})
this.$router.replace({ // 替換,但history不會記錄一條新的記錄 path: '/mypath', query: {m: 'model'}, })
路徑:http://localhost:8081/#/test?name=1 <router-link :to="{path:'/test',query: {name: id}}">跳轉</router-link>(id是參數) 路徑:http://localhost:8081/#/test/1 <router-link :to="'/test/'+id">跳轉</router-link>(id是參數)
params、query是什麼?
params:/router1/:id ,/router1/123,/router1/789 , 這裏的id叫作params, 且路由時必需傳id
params:/router1/:id? ,/router1/123,/router1 , 這裏的id叫作params, 路由時可不傳id
query:/router1?id=123 ,/router1?id=456 , 這裏的id叫作query,路由時可不傳idnode
this.$route.params.id
this.$route.query.id
watch: { obj: { handler: function (v, o) { }, deep: true } }
<template> <article class="pageview"> {{msg}} </article> </template> <script> import {mapState, mapMutations} from 'vuex' export default { name: 'Home', mixins: [], components: { }, data () { return { msg: 'Home', } }, beforeCreate () { }, created () { }, mounted () { }, beforeUpdate () { }, updated () { }, beforeDestroy () { }, destroyed () { }, methods: { }, computed: { }, filters: { } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style lang="scss" scoped> </style
router.beforeEach((to, from, next) => { if (to.meta.title) { document.title = to.meta.title // 動態設置meta或者能夠進行其餘路由前的操做 } NProgress.start() // NProgress進度條開始 next() }) router.afterEach((transition) => { NProgress.done() // NProgress進度條結束 })
axios.interceptors.request.use((headerConfig)=> { // 這裏,發送請求以前能夠設置request header return config }, (error) => { // 請求錯誤處理 return Promise.reject(error) }) // 添加響應攔截器 axios.interceptors.response.use((response) => { let {data} = response // 這裏,請求完成後能夠對數據進行攔截處理 return data }, (error) => { // 響應錯誤處理 return Promise.reject(error) })
last 10 versionsreact
修改 config/index.js 文件android
寫法1、使用filter統一代理ios
proxyTable: { '**': { target: 'https://www.xxxx.com', // 要設置需跨域訪問的接口的baseUrl,dev/qa/production changeOrigin: true, filter: function(pathname, req) { const isApiDev = pathname.indexOf('/api-dev/') == 0; const isApiTest = pathname.indexOf('/api-qa/') == 0; const isApiProduction = pathname.indexOf('/api-production/') == 0; return isApiDev||isApiTest||isApiProduction ; } } }
寫法2、使用pathRewrite的寫法
proxyTable: { '/api/resource': { target: 'https://xxx.xxx.xxx.xxx:7070', changeOrigin: true, secure: false, pathRewrite: { '^/api/resource'': '/resource' } }, },
解決方案,使用/deep/
<template> <div id="app"> <el-input v-model="text" class="text-box"></el-input> </div> </template> <script> export default { name: 'App', data() { return { text: 'hello' }; } }; </script> <style lang="less" scoped> .text-box { // 樣式能夠做用於el-input 組件 /deep/ input { width: 166px; text-align: center; } } </style>
簡單的登陸+是否VIP會員的鑑權寫法以下
import router from './router' import NProgress from 'nprogress' // Progress 進度條 import 'nprogress/nprogress.css' // Progress 進度條樣式 NProgress.inc(0.2) NProgress.configure({ easing: 'ease', speed: 500, showSpinner: false }) router.beforeEach((to, from, next) => { const isLogin = false // 是否登陸 const isVip= false // 是否VIP會員 NProgress.start() if (isLogin && isVip) { if (to.path.indexOf('/login') !== -1 || to.path.indexOf('/order-vip') !== -1) { next('/home') NProgress.done() } else { if (to.meta.title) { document.title = to.meta.title } next() } } else if (isLogin && !isVip) { if (to.path.indexOf('/login') !== -1 || to.path.indexOf('/home') !== -1) { next('/order-vip') NProgress.done() } else { if (to.meta.title) { document.title = to.meta.title } next() } } else { if (to.path.indexOf('/login') !== -1) { if (to.meta.title) { document.title = to.meta.title } next() } else { next('/login') // 不然所有重定向到登陸頁 NProgress.done() } } }) router.afterEach(() => { NProgress.done() // 結束Progress })
一、修改config目錄下的index.js
build: { // Template for index.html index: path.resolve(__dirname, '../dist/index.html'), // Paths assetsRoot: path.resolve(__dirname, '../dist'), assetsSubDirectory: 'static', assetsPublicPath: '', // 修改這裏由「/」改成「./」或者「」
二、修改build目錄下的utils.js
if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, fallback: 'vue-style-loader', publicPath: '../../' // 增長相對路徑,主要是針對css背景圖 })
在小型的vue項目當中,其實並不須要使用到vuex,使用全局變量便可,使用方式:直接在main.js裏面定義便可
/** * 全局變量定義 * */ global.USER_ID = null global.USER_NAME = null global.USER_MOBILE = null
固然也能夠在main.js中把常量或者方法掛載到Vue的原型鏈prototype上,而後在頁面中就能夠直接經過this.xxx直接使用,如:
import axios from 'axios' import { Toast, MessageBox, Indicator, DatetimePicker } from 'mint-ui' Vue.use(DatetimePicker) Vue.prototype.SUCCESS_CODE = 0 Vue.prototype.$toast = Toast Vue.prototype.$messagebox = MessageBox Vue.prototype.$indicator = Indicator Vue.prototype.axios = axios
解決方式:在main.js引入babel-polyfill
import 'babel-polyfill'
若是同時使用style及:style去分開設置background:url(xxx)及background-size:xx xx的話,後面設置的background-size會失效,可使用下面的方式來設置解決
background: url(https://www.xxx.com/xxx.jpg) center center / 100% 100% no-repeat;
服務器端可以使用Cache-Control: max-age=xxxx 來控制靜態文件緩存時間,相似以下:
// 服務端代碼 app.get('/xxxx.js', (req, res) => { res.setHeader('Cache-Control', 'max-age=3600') // ...其餘輸出 })
watch: { '$route' (to, from) { // 針對變化進行相應的處理 } }
解決方法:把 config/index.js文件中的localhost改成本地IP就好了,而後後面再改回來試試,或者再檢查一下localhost指向不對了(host文件)
當你在平時的帶有node-sass依賴包的vue項目中執行yarn dev或者npm run dev時,會報錯,大概報錯以下:
Node Sass could not find a binding for your current environment This usually happens because your environment has changed since running `npm install` Run `npm rebuild node-sass` to build the binding for your current environment
而後,rebuild就rebuild唄,結果還發現因爲牆的緣由,二進制文件地址(https://github-production-release-asset-2e65be.s3.amazonaws.com/4128353/585e4c80-9c28-11e8-8cdf-78861f5b0424?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20190220%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190220T104233Z&X-Amz-Expires=300&X-Amz-Signature=12d9dd3497845f932f0926c62c2c02ace2b12095f8212a70957430c2b706aadb&X-Amz-SignedHeaders=host&actor_id=7983722&response-content-disposition=attachment%3B%20filename%3Dwin32-x64-64_binding.node&response-content-type=application%2Foctet-stream)一直下載失敗,一直rebuild失敗
1)切換到聯通4G把文件下載到本地如(D:\temp\win32-x64-48_binding.node )
2)執行命令:set SASS_BINARY_PATH=D:\temp\win32-x64-48_binding.node
3)執行npm rebuild node-sass 成功啦,最後,執行yarn dev或者npm run dev應該沒問題了。
不作緩存策略會存在的問題:微信下打開總會load到舊包或者會出現白屏狀況
vue項目打包發佈時生成的靜態包文件要發佈上線時可選用的策略:
1)若是用戶訪問量大的,服務器能夠設置cache control及增量發包
2)若是系統用戶數訪問量不大的,能夠設置html添加meta設計cache-control爲no-cache或者其餘,也能夠結合服務器一塊兒配置
iphone X系列頁面偶爾會出現因頁面變換而渲染失敗的狀況,引用scrollIntoViewIfNeeded能夠強制滾動頁面讓其從新渲染出來
npm install --save babel-polyfill
在main.js文件頭部引入
import 'babel-polyfill' // 或者require('babel-polyfill')
computed: { fullname: { // getter get: function () { return this.firstName + this.familyName }, // setter set: function (newValue) { let names = newValue.split(' ') this.firstName = names[0] this.familyName = names[1] } } }
在template上加上組件引用標識ref,相似於之前的react組件引用方式
<my-component ref="myComponent" />
而後在js代碼中直接使用
this.$refs.myComponent.fn() // 好比組件上有fn這個內置方法,直接調用
使用render函數即其中的h函數進行處理,可參照:Vue中使用渲染函數render實現無限節點的樹
router.beforeEach((to, from, next) => { // 全部if else條件都必需提供next路由出口,否則會出現死詢環(不停加載)或者路由失敗(白屏的狀況) })
解決方式:給路由後的fixed內容加寬度限制
max-width: 10rem; /* 750px; */
axios({ url: '/api', method: 'post', data: { param1:param1, param2:param2 }, transformRequest: [function (data) { let ret = '' for (let it in data) { ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&' } return ret }], headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
<div v-html="message">{{message}}</div> export default { data () { return { message: "<h2>這裏能夠包含html標籤<h2>" } } }
解決方案:讓事件異步執行
methods: { handleClick () { setTimeout(() => { this.$router.go(-1) // 或者其餘關閉對話框事件等等 }, 0) } }
<script> // Vue子組件定義事件event1 Vue.component('child-component', { methods: { emitEvent() { this.$emit('event1', 'This is a event.') } }, mounted() { this.emitEvent() } }) </script> // Vue 父組件綁定監聽子組件事件event1 <template> <div> <child-component @event1="eventHandler" /> </div> </template> <script> import childComponent from './child-component' export default { components: { childComponent }, methods: { eventHandler(event) { console.log(event) } } } </script>
mutations: { UPDATE_STATE: (state, options) => { // state = { ...state, ...options } // 此方式可能會更新失敗 Object.keys(options).forEach((key) => { // 使用Vue.set強制更新 Vue.set(state, key, options[key]) }) } },
使用 <keep-alive>或者使用scrollIntoView與scrollIntoViewIfNeed
好比若是在vue內頁中使用
let myUrl = './static/js/a.js' // build出來後是 相對於http://xxx/xx/index.html的,結果爲 http://xxx/xx/static/js/a.js
1、如何引用本地的圖片?
// 若是要使用一張圖片,能夠先把img import進來再畫到canvas上, import myImg from '../../assets/my-img.png' // ... export default { // ... data () { return { myImg: myImg } }, // ... }
2、圖片請求時是來源於外域,但canvas最後要使用btoa、canvas.toDataURL()時,瀏覽器是不容許跨域把canvas轉成圖片的。
解決辦法是要,圖片服務器設置容許跨域請求,同時<img >要加上crossOrigin="anonymous"屬性,告訴頁面圖片將要經過跨域請求。
可參考:
https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror/27260385#27260385
https://www.jianshu.com/p/6fe06667b748
刪除placeholder或者本身額外添加假placeholder
參考:https://blog.csdn.net/siwangdexie_copy/article/details/89947594
問題:當使用class樣式結合setTimeout進行組合動畫時,若是使用了dom操做來添加或者修改動畫,此時,若是過程當中state值發生了變化,有可能致使動畫失效(dom被從新渲染了)
解決方式:應當儘量使用減小直接對dom的操做,更多的使用直接變動state切換class或者v-if、v-show來結合setTimeout來建立組合動畫。
解決方式:在error後面添加error.response
/* 解決element-ui的table表格控件表頭與內容列不對齊問題 */ /deep/ .el-table th.gutter { display: table-cell !important; }
// blob二進制方式 axios({ method: 'post', url: '/api/exportExcel', headers: { 'Content-Type': 'application/json' }, data: { token: 'xxxx', } }).then((res) => { // console.log(res) const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' }) // application/vnd.openxmlformats-officedocument.spreadsheetml.sheet這裏表示xlsx類型 const downloadElement = document.createElement('a') const href = window.URL.createObjectURL(blob) // 建立下載的連接 downloadElement.href = href downloadElement.download = 'xxxx.xlsx' // 下載後文件名 document.body.appendChild(downloadElement) downloadElement.click() // 點擊下載 document.body.removeChild(downloadElement) // 下載完成移除元素 window.URL.revokeObjectURL(href) // 釋放掉blob對象 }).catch((error) => { console.log(error.message) })
arraybuffer方式也相似,可參考:http://www.javashuo.com/article/p-xvpotevd-ke.html
<template> <div> <label><input type="checkbox" :checked="value" @click="change" /> 勾選我吧</label> </div> </template> <script> export default { data() { }, model:{ prop:'value', event:'valueChange' }, props:{ value: Number }, methods:{ change(e) { let number = 0 if(e.target.checked) { number = 1 } this.$emit('valueChange', number) } } } </script>
問題所在就是代碼段同時出現了import與module.exports
解決方案:去掉module.export,使用統一ES6的方式編寫便可,用export default代替