【vue】常见开发知识点与问题整理(持续更新)
1.vue雙向數據綁定vuex中的state
在vue中, 不允許直接綁定vuex的值到組件中, 若是直接使用, 則會報錯 have no setter
方法一: 使用get和set
// 在從組件的computed中
computed: {
user: {
get() {
return this.$store.state.user
},
set(v) {
// 使用vuex中的mutations中定義好的方法來改變
this.$store.commit('USER', v)
}
}
}
// 在組件中就可以使用
<input v-modle="user" />
方法二: 使用watch
// 在組件中綁定
<input v-modle="user" />
// 在computed中獲取vuex的值
computed: {
...mapState( { user: state => state.user } )
}
// 在組件的watch中觀測
watch: {
'user': {
deep: true,
handler(value) {
// 使用vuex中的mutations中定義好的方法來改變
this.$store.commit('USER', value)
}
}
}
2.(webpack)vue-cli構建的項目如何設置每個頁面的title
在路由里每個都添加一個meta:
[{
path:'/login',
meta: {
title: '登錄頁面'
},
component:'login'
}]
鉤子函數,在main.js中添加如下代碼:
router.beforeEach((to, from, next) => {
window.document.title = to.meta.title;
next()
})
3.vue項目中使用axios上傳圖片等文件
通過form表單提交,html代碼如下:
<input name="file" type="file" accept="image/png,image/gif,image/jpeg" @change="update"/>
JS代碼:
import axios from 'axios'
update(e) {
let file = e.target.files[0]
let param = new FormData(); // 創建form對象
param.append('file', file); // 通過append向form對象添加數據
param.append('chunk', '0'); // 添加form表單中其他數據
let config = { // 添加請求頭
headers: {
'Content-Type': 'multipart/form-data'
}
};
axios.post('http://172.19.26.60:8080/user/headurl', param, config)
.then(response => {
if (response.data.code === 200) {
this.ImgUrl = response.data.data;
}
})
}
4.qs.stringify() 和JSON.stringify()的區別、vux中使用post提交表單數據需要qs庫序列化
qs庫的npm地址:https://www.npmjs.com/package/qs
功能雖然都是序列化。假設我要提交的數據如下:
var a = {name:'hehe',age:10};
qs.stringify序列化結果如下:name=hehe&age=10
而JSON.stringify序列化結果如下:"{"a":"hehe","age":10}"
vux中使用post提交表單數據:
this.$http.post(this.$sign.config.url.loginUrl,this.$qs.stringify({
"phone":this.phoneNumber,
"vCode":this.loginCode,
"smsCode":this.phoneCode
})
)
.then(response=>{
console.log(response.data);
if(response.data.httpCode == 200){
}else{
}
})
在firebug中可以看到傳遞的參數:phone=15210275239&vCode=8vsd&smsCode=1534
在vue中使用axios:
this.$axios.post(loginUrl, {
"email": this.email,
"password": this.password
}, {
transformRequest: (data) => {
return this.$qs.stringify(data)
},
}).then(res => {
if(res.data.resultCode == RESULT_CODE_SUCCESS){
console.log('登錄成功');
this.$router.push({name:"home"})
}else{
console.log('登錄失敗');
}
}).catch(err => {
console.log('登登錄出現錯誤');
})
5.vue全局實現的setCookie、getCookie、delCookie
//設置cookie,增加到vue實例方便全局調用
Vue.prototype.setCookie = (c_name, value, expiredays) => {
var exdate = new Date();
exdate.setDate(exdate.getDate() + expiredays);
document.cookie = c_name + "=" + escape(value) + ((expiredays == null) ? "" : ";expires=" + exdate.toGMTString());
}
//獲取cookie
Vue.prototype.getCookie = (name) => {
var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
if (arr = document.cookie.match(reg)){
return (arr[2]);
}
return null;
}
//刪除cookie
Vue.prototype.delCookie =(name) => {
var exp = new Date();
exp.setTime(exp.getTime() - 1);
var cval = this.getCookie(name);
if (cval != null){
document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
}
}
6.webpack proxyTable 代理跨域
webpack 開發環境可以使用proxyTable 來代理跨域,生產環境的話可以根據各自的服務器進行配置代理跨域就行了。在我們的項目config/index.js 文件下可以看到有一個proxyTable的屬性,我們對其簡單的改寫:
proxyTable: {
'/api': {
target: 'http://api.douban.com/v2',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
這樣當我們訪問localhost:8080/api/movie的時候 其實我們訪問的是http://api.douban.com/v2/movie這樣便達到了一種跨域請求的方案。
當然我們也可以根據具體的接口的后綴來匹配代理,如后綴為.shtml,代碼如下:
proxyTable: {
'**/*.shtml': {
target: 'http://192.168.198.111:8080/abc',
changeOrigin: true
}
}
可參考地址:
webpack 前后端分離開發接口調試解決方案,proxyTable解決方案
http-proxy-middleware
7.vue和mintui-Loadmore結合實現下拉刷新,上拉加載 (待優化)
mintui是餓了么團隊針對vue開發的移動端組件庫,方便實現移動端的一些功能,這里只用了Loadmore功能實現移動端的上拉分頁刷新,下拉加載數據.
mintui官網:http://mint-ui.github.io/
<template>
<div class="main-body" :style="{'-webkit-overflow-scrolling': scrollMode}">
<v-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" :auto-fill="false" ref="loadmore">
<ul class="list" v-for="(val, key) in pageList">
<li>
<div>我是小11</div>
<div>我是小11</div>
</li>
</ul>
</v-loadmore>
</div>
</template>
<script>
import {Loadmore} from 'mint-ui';
export default {
data:function() {
return {
searchCondition:{ //分頁屬性
pageNo:"1",
pageSize:"10"
},
pageList:[],
allLoaded: false, //是否可以上拉屬性,false可以上拉,true為禁止上拉,就是不讓往上劃加載數據了
scrollMode:"auto" //移動端彈性滾動效果,touch為彈性滾動,auto是非彈性滾動
}
},
components: {
'v-loadmore':Loadmore // 為組件起別名,vue轉換template標簽時不會區分大小寫,例如:loadMore這種標簽轉換完就會變成loadmore,容易出現一些匹配問題
// 推薦應用組件時用a-b形式起名
},
mounted(){
this.loadPageList(); //初次訪問查詢列表
},
methods: {
loadTop:function() { //組件提供的下拉觸發方法
//下拉加載
this.loadPageList();
this.$refs.loadmore.onTopLoaded();// 固定方法,查詢完要調用一次,用于重新定位
},
loadBottom:function() {
// 上拉加載
this.more();// 上拉觸發的分頁查詢
this.$refs.loadmore.onBottomLoaded();// 固定方法,查詢完要調用一次,用于重新定位
},
loadPageList:function (){
// 查詢數據
this.api.PageList(this.searchCondition).then(data =>{
// 是否還有下一頁,加個方法判斷,沒有下一頁要禁止上拉
this.isHaveMore(data.result.haveMore);
this.pageList = data.result.pageList;
this.$nextTick(function () {
// 原意是DOM更新循環結束時調用延遲回調函數,大意就是DOM元素在因為某些原因要進行修改就在這里寫,要在修改某些數據后才能寫,
// 這里之所以加是因為有個坑,iphone在使用-webkit-overflow-scrolling屬性,就是移動端彈性滾動效果時會屏蔽loadmore的上拉加載效果,
// 花了好久才解決這個問題,就是用這個函數,意思就是先設置屬性為auto,正常滑動,加載完數據后改成彈性滑動,安卓沒有這個問題,移動端彈性滑動體驗會更好
this.scrollMode = "touch";
});
});
},
more:function (){
// 分頁查詢
this.searchCondition.pageNo = parseInt(this.searchCondition.pageNo) + 1;
this.api.loadPageList(this.searchCondition).then(data=>{
this.pageList = this.pageList.concat(data.result.pageList);
this.isHaveMore(data.result.haveMore);
});
},
isHaveMore:function(isHaveMore){
// 是否還有下一頁,如果沒有就禁止上拉刷新
this.allLoaded = true; //true是禁止上拉加載
if(isHaveMore){
this.allLoaded = false;
}
}
}
}
</script>
PS:有個坑一定要注意就是注釋里說的iPhone里loadmore和-webkit-overflow-scrolling屬性沖突無法上拉問題
可參考另外一個插件,沒有使用過,《簡單靈活且強大的Vue下拉刷新組件:vue-pull-to》
8.vue非父子組件通信
如果2個組件不是父子組件那么如何通信呢?這時可以通過eventHub來實現通信。所謂eventHub就是創建一個事件中心,相當于中轉站,可以用它來傳遞事件和接收事件。
方式一
組件1觸發:
<div @click="eve"></div>
methods: {
eve() {
Hub.$emit('change','hehe'); //Hub觸發事件
}
}
組件2接收:
created() {
Hub.$on('change', (msg) => { //Hub接收事件
this.msg = msg;
});
}
可參考:vue非父子組件怎么進行通信
方式二
把中轉站數據存放到根實例下面,如下:
// 根組件(this.$root)
new Vue({
el: '#app',
router,
render: h => h(App),
data: {
// 空的實例放到根組件下,所有的子組件都能調用
Bus: new Vue()
}
})
組件1觸發:
<div @click="eve"></div>
methods: {
eve() {
this.$root.Bus.$emit('change','hehe');
}
}
組件2接收:
created() {
this.$root.Bus.$on('change', (msg) => { //接收事件
this.msg = msg;
});
}
注:官方推薦的eventbus 解決方案的缺陷在于, 在數據傳遞過程中,兩個組件必須都已經被渲染過。
9.IE9報vuex requires a Promise polyfill in this browser問題解決
因為使用了 ES6 中用來傳遞異步消息的的Promise,而IE低版本的瀏覽器不支持。
解決方法
第一步: 安裝 babel-polyfill
babel-polyfill可以模擬ES6使用的環境,可以使用ES6的所有新方法
npm install --save-dev babel-polyfill
第二步: 在 Webpack/Browserify/Node中使用
在webpack.config.js文件中把
module.exports = {
entry: {
app: './src/main.js'
}
}
替換為:
module.exports = {
entry: {
app: ["babel-polyfill", "./src/main.js"]
}
};
當然還有其它兩種引入方式:
require("babel-polyfill");
import"babel-polyfill";
10.啟動Vue項目時提示: [BABEL] ... max of "500KB".
在項目的根目錄下找到 .babelrc 文件,增加 "compact": false ,如:
{
"compact": false,
"presets": ["env", "react", "stage-0"],
"plugins": [
"transform-runtime"
]
}
如果不存在則手動創建該文件,并填寫內容如:
{
"compact": false
}
11.在main.js中監聽微信瀏覽器返回按鈕,讓其不能返回
if(from.name == 'staffInfo' && to.name == 'Login'){
next({path:'/staffInfo',query:{redirect:from.fullPath}});
}else if(from.name == 'acountFill' && to.name == 'Login'){
next({path:'/acount/acountFill',query:{redirect:from.fullPath}});
}
12.pdf.js默認不顯示電子簽章(數字簽名)問題解決
1. pdfjs 舊版本
pdf.worker.js 找到
if(this.data.fieldType === 'Sig') {
warn('unimplemented annotation type: Widget signature');
return false;
}
注解上面代碼.
2. pdfjs 新 版本v1.10.88
pdf.worker.js 找到
if(data.fieldType === 'Sig') {
_this2.setFlags(_util.AnnotationFlag.HIDDEN);
}
13.pdf.js預覽,中文顯示亂碼解決方法
有可能是有pdf不支持的字體格式,引入pdf.js的字體試試
const CMAP_URL = 'https://unpkg.com/pdfjs-dist@2.0.489/cmaps/';
pdfjsLib.getDocument({
data: pdfData,
cMapUrl: CMAP_URL,
cMapPacked: true,
})
14.解決Vue引入百度地圖JSSDK:BMap is undefined 問題
export default {
init: function (){
//console.log("初始化百度地圖腳本...");
const AK = "AK密鑰";
const BMap_URL = "https://api.map.baidu.com/api?v=2.0&ak="+ AK +"&s=1&callback=onBMapCallback";
return new Promise((resolve, reject) => {
// 如果已加載直接返回
if(typeof BMap !== "undefined") {
resolve(BMap);
return true;
}
// 百度地圖異步加載回調處理
window.onBMapCallback = function () {
console.log("百度地圖腳本初始化成功...");
resolve(BMap);
};
// 插入script腳本
let scriptNode = document.createElement("script");
scriptNode.setAttribute("type", "text/javascript");
scriptNode.setAttribute("src", BMap_URL);
document.body.appendChild(scriptNode);
});
}
}
說明:
直接使用官網提供的引用地址:http://api.map.baidu.com/api?v=2.0&ak=您的密鑰
啟用 callback 參數,異步加載必須使用此參數才可以生效
啟用 https 配置,通過 s=1 參數實現
API版本為2.0,經測試使用,發現3.0版本在HTTPS環境下是有問題的,腳本內部某些請求固定使用HTTP,無法正常使用。
參考地址:https://segmentfault.com/a/1190000012815739
15.本地啟動vue項目,host配置域名訪問出現Invalid Host header 服務器域名訪問出現的問題
在webpack.dev.config.js中找到 devServer下的hot,再下面添加 disableHostCheck: true,來解決127.0.0.1指向其他域名時出現"Invalid Host header"問題
如圖所示:
16.vue項目中在使用vue-router切換頁面的時候滾動條怎樣自動滾動到頂部?
有時候我們需要頁面滾動條滾動到某一固定的位置,一般使用WindowscrollTo() 方法。
語法就是:scrollTo(xpos,ypos)
xpos:必需。要在窗口文檔顯示區左上角顯示的文檔的 x 坐標。
ypos:必需。要在窗口文檔顯示區左上角顯示的文檔的 y 坐標。
例如滾動內容的坐標位置100,500:
window.scrollTo(100,500);
好了,這個scrollTop這兒只是簡單介紹一下,下面我們介紹下veu-router中的滾動行為。
使用前端路由,當切換到新路由時,想要頁面滾到頂部,或者是保持原先的滾動位置,就像重新加載頁面那樣。vue-router能做到,而且更好,它讓你可以自定義路由切換時頁面如何滾動。
注意: 這個功能只在HTML5 history 模式下可用。
當創建一個 Router 實例,你可以提供一個scrollBehavior方法:
const router = new VueRouter({
routes: [...],
scrollBehavior (to, from, savedPosition) {
// return 期望滾動到哪個的位置
}
})
scrollBehavior方法接收to和from路由對象。第三個參數savedPosition當且僅當popstate導航 (通過瀏覽器的 前進/后退 按鈕觸發) 時才可用。
這個方法返回滾動位置的對象信息,長這樣:
{ x: number, y: number }
{ selector: string, offset? : { x: number, y: number }}(offset 只在 2.6.0+ 支持)
如果返回一個 falsy (譯者注:falsy 不是false,參考這里)的值,或者是一個空對象,那么不會發生滾動。
舉例:
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
對于所有路由導航,簡單地讓頁面滾動到頂部。
返回savedPosition,在按下 后退/前進 按鈕時,就會像瀏覽器的原生表現那樣
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
如果你要模擬『滾動到錨點』的行為:
scrollBehavior (to, from, savedPosition) {
if (to.hash) {
return {
selector: to.hash
}
}
}
我們還可以利用路由元信息更細顆粒度地控制滾動。
routes: [
{ path: '/', component: Home, meta: { scrollToTop: true }},
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar, meta: { scrollToTop: true }}
]
完整的例子:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const Home = { template: '<div>home</div>' }
const Foo = { template: '<div>foo</div>' }
const Bar = {
template: `
<div>
bar
<div></div>
<p id="anchor">Anchor</p>
</div>
`
}
// scrollBehavior:
// - only available in html5 history mode
// - defaults to no scroll behavior
// - return false to prevent scroll
const scrollBehavior = (to, from, savedPosition) => {
if (savedPosition) {
// savedPosition is only available for popstate navigations.
return savedPosition
} else {
const position = {}
// new navigation.
// scroll to anchor by returning the selector
if (to.hash) {
position.selector = to.hash
}
// check if any matched route config has meta that requires scrolling to top
if (to.matched.some(m => m.meta.scrollToTop)) {
// cords will be used if no selector is provided,
// or if the selector didn't match any element.
position.x = 0
position.y = 0
}
// if the returned position is falsy or an empty object,
// will retain current scroll position.
return position
}
}
const router = new VueRouter({
mode: 'history',
base: __dirname,
scrollBehavior,
routes: [
{ path: '/', component: Home, meta: { scrollToTop: true }},
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar, meta: { scrollToTop: true }}
]
})
new Vue({
router,
template: `
<div id="app">
<h1>Scroll Behavior</h1>
<ul>
<li><router-link to="/">/</router-link></li>
<li><router-link to="/foo">/foo</router-link></li>
<li><router-link to="/bar">/bar</router-link></li>
<li><router-link to="/bar#anchor">/bar#anchor</router-link></li>
</ul>
<router-view class="view"></router-view>
</div>
`
}).$mount('#app')
在網上查了一下,網友說還可以試試在main.js入口文件配合vue-router寫這個
router.afterEach((to,from,next) => {
window.scrollTo(0,0);
});
17.tips:webpack中alias配置中的“@”的作用
如題所示,build文件夾下的webpack.base.conf.js
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src')
}
}
其中的@的意思是:只是一個別名而已。這里設置別名是為了讓后續引用的地方減少路徑的復雜度。
//例如
src
- components
- a.vue
- router
- home
- index.vue
index.vue 里,正常引用 A 組件:
import A from '../../components/a.vue'
如果設置了 alias 后。
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src')
}
引用的地方路徑就可以這樣了
import A from '@/components/a.vue'
這里的 @ 就起到了【resolve('src')】路徑的作用。
18.tips:package.json中的dependencies與devDependencies之間的區別
–save-dev和–save的區別
我們在使用npm install 安裝模塊或插件的時候,有兩種命令把他們寫入到 package.json 文件里面去,比如:
–save-dev 安裝的 插件,被寫入到 devDependencies 對象里面去
–save 安裝的 插件 ,被寫入到 dependencies 對象里面去
devDependencies是只會在開發環境下依賴的模塊,生產環境不會被打入包內。
dependencies是不僅在開發環境使用,在生成環境也需要。
19.tips:package.json設置環境變量
三種方法可以在package.json設置環境變量。
先安裝cross-env:
npm install --save-dev cross-env
package.json設置:
{
"scripts": {
"dev1": "export WEBPACK_ENV=production && npx webpack -p", ## mac
"dev1": "set WEBPACK_ENV=production && npx webpack -p", ## windows
"dev2": "cross-env CURRENT_ENV=development webpack-dev-server --inline --progress", ## 兼容所有平臺
}
}
設置環境變量的作用:
在項目的js腳本中,通過process.env這個對象就可以訪問到設置的環境變量結合打包軟件webpack等等,實現不同的代碼邏輯:
console.log(process.env.WEBPACK_ENV) console.log(process.env.CURRENT_ENV)
擴展參考:阮一峰:npm scripts 使用指南
總結
以上是生活随笔為你收集整理的【vue】常见开发知识点与问题整理(持续更新)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一文让你彻底了解大数据实时计算引擎 Fl
- 下一篇: 好听的古代女子名字大全860个