第一次與vue親密接觸的挖坑和填坑之路

1. vuex以及本地存儲localStorage如何實現(xiàn)登錄之后在刷新的時候登錄狀態(tài)仍然在。

借鑒這篇回答:如何使用localStorage結(jié)合Vuex來保存用戶登錄信息?

遇到問題——當時是期待根據(jù)localStorage中的值的改變在計算屬性中隨時得到新的值。事實上。vue中的值并不會因為localStorage中值的改變而變化的,觸發(fā)不了。所以完美的辦法就是所有和localStorage相關(guān)的都在vuex中處理,這樣狀態(tài)就可以實時改變了。

當時我的問題是——我想每次進入頁面后檢測現(xiàn)在localStorage中是否有登錄的信息,有的話就從localStorage中取,沒有的話從vuex中取,這步其實就是等待登錄后拿到值,然后在我退出登錄時,我清空localStorage里面的值,此時就不能進行一些操作或者一些顯示。。。。我是在計算屬性中獲取的。

后來借鑒上文的回答,一進入頁面觸發(fā)vuex,去把localStorage中的值給vuex中的狀態(tài)值,然后在組件中只是用狀態(tài)值就行。所有l(wèi)ocalStorage的設(shè)置值和移除值均在vuex中完成。

整個處理方式就是這樣的,很重要,要記住。由于項目在后面改變了方式,所以我又改變了不再使用localStorage來儲存值了。

//一進入頁面
created(){
    this.getLocalData();
},
methods:{
    ...mapActions({
        getLocalData:'getLocalData',
    }),
}
//vuex中
getLocalData({commit}){
    commit(types.GET_LOCALDATA);
},

[types.GET_LOCALDATA] (state){
    if(localStorage.id)
        state.sfz = localStorage.sfz;
        state.user = localStorage.id;
        state.pwd = localStorage.pwd;
        state.loginFlag = false;
    }
    
},
//退出登錄
[types.LOGIN_OUT] (state){
    localStorage.removeItem('id');
    localStorage.removeItem('sfz');
    localStorage.removeItem('pwd');
    state.user = '';
    state.sfz ='';
    state.pwd ='';
    state.loginFlag = true;
    
},

2. Computed property "digitalCert" was assigned to but it has no setter 報錯

問題分析: 一個計算屬性,如果沒有設(shè)置 setter,也就是傳入的是一個函數(shù),或者傳入的對象里沒有 set 屬性,當你嘗試直接該改變這個這個計算屬性的值,都會報這個錯誤。

在此項目中,我寫了:

mounted() {
var _this = this;
document.onkeydown=function(e) {
    if(e && e.keyCode==81 && e.ctrlKey ){   //同時按下ctrl+q
        _this.digitalCert = false;   
}
           

所以更改為以下:

computed:{
    digitalCert:{
        get:function(){
            return this.$store.state.login.digitalCert;
        },
        set:function(newValue){
            this.$store.state.login.digitalCert = newValue;
        }
    }
},

3. 在引入mapState的計算屬性時,怎么寫普通的計算屬性,以及設(shè)置getter和setter的計算屬性:

有g(shù)etter和setter

computed:{
    digitalCert:{
        get:function(){
            return this.$store.state.login.digitalCert;
        },
        set:function(newValue){
            this.$store.state.login.digitalCert = newValue;
        }
    },
    ...mapState({
        loginBoxFlag: state => state.login.loginBoxshow,
        tipsTxt: state => state.login.tipsTxt,
    }),
},

普通計算屬性

// mapState 輔助函數(shù)幫助我們生成計算屬
computed: mapState({
    // 箭頭函數(shù)可使代碼更簡練
    count: state => state.count,
    // 傳字符串參數(shù) 'count' 等同于 'state => state.count'
    countAlias: 'count',
    // 為了能使用 'this'獲取局部狀態(tài),必須使用常規(guī)函數(shù)
    countPlusLocalState (state) {
        return state.count + this.localCount
    },
    // 常規(guī) computed, 沒有使用 store的狀態(tài)
    localCountAlias () {
        return this.localCount
    }
})

4.vuex中的請求寫成promise格式的好處。

在vuex的action里面的請求要寫成promise的形式。舉例如我所做的logout。事實上登錄的很多狀態(tài)我也可以不在vuex里面維護的,沒有必要,一開始不明白這個道理:

//在header.vue中點擊按鈕觸發(fā)logout方法
logout() {
    let _this  = this;
    this.$confirm('你確定要注銷登錄嗎?', '提示', {
        confirmButtonText: '確定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
        _this.$store.dispatch('loginOut')
    }).then(() =>{
        _this.searchValue = '';//就可以這樣清除本組件中的值,不需要去vuex中實現(xiàn)
        _this.$message({
            type: 'success',
            message: '你已經(jīng)成功退出登錄'
        });
    }).catch((e) => {
        this.$message({
            type: 'info',
            message: '已取消注銷登錄'
        });          
    });
  }

在vuex中維護:

//actions中:
loginOut:({dispatch,commit})=> {
    return new Promise((resolve, reject) => {
        utils.MlTools.ajax({
            type:'get',
            url:'/qbeq/userLogOut',
            success:function(datas){
                if(datas.code){
                    commit(types.LOGIN_OUT)
                    resolve(datas)
                }
                    
            },
            error:function(res){
                console.log(res)
                reject(datas)
            }
        })
        
    })
}

//在mutations中:
[types.LOGIN_OUT] (state){
    state.user = '';
    state.sfz ='';
    state.pwd ='';
    state.loginFlag = true;
    
},

重點就想說明在actions中resolve()之后,在vue組件的then之后即為退出成功的處理了。

5. 數(shù)組初始化在data中而非在computed中;數(shù)組的更新必須vue.set

初始化data之后,要在請求中對這個數(shù)進行賦值,那么不能在computed中初始化,比如將這個數(shù)組的每一個元素都初始化為0;

data (){
    return {
        trendValueIn:new Array(10).join(",").split(",").map((item,index) => {return 0;}),
        trendValueOut:new Array(10).join(",").split(",").map((item,index) => {return 0;}),
    }
   
},
computed:{
    // trendValueIn(){
    //     return new Array(10).join(",").split(",").map((item,index) => {return 0;})
    // },
    // trendValueOut(){
    //     return new Array(10).join(",").split(",").map((item,index) => {return 0;})
    // },
},
created(){
    this.reqRrendValue()
},
methods:{
    reqRrendValue(){
        let _this = this;
        this.utils.MlTools.ajax({
            url: '/qbeq/keyperson',
            type: 'post',
            data: {},
            success(data){
                _this.createdtable(data.currDay);
                _this.drawLine(data.totalDay);
            },
            error(err){
                reject(err.message)
            }
        })
    },
    createdtable(data){
        let _this = this;
        
        //今日流入
        let todayDataIn = data.filter((n,m) => {
            if(n.flag == 1){
                return n;
            }
        })
        //今日流出
        let todayDataOut = data.filter((n,m) => {
            if(n.flag == 0){
                return n;
            }
        })
        //總共的
        let totalIn = 0,totalOut = 0;
        todayDataIn.forEach((item,index) => {
            let i = _this.theader.findIndex((value,index) => {
                return value == item.type;
            })
            totalIn += item.num; 
            // _this.trendValueIn[i] = item.num;
            _this.$set(_this.trendValueIn,i-1,item.num)//更新數(shù)組需要使用vue.set
        })
        _this.$set(_this.trendValueIn,9,totalIn)
    
        todayDataOut.forEach((item,index) => {
            let i = _this.theader.findIndex((value,index) => {
                return value == item.type;
            })
            totalOut += item.num; 
            // _this.trendValueOut[i] = item.num;
            _this.$set(_this.trendValueOut,i-1,item.num)//更新數(shù)組需要使用vue.set
        })
        _this.$set(_this.trendValueOut,9,totalOut)
    },
}

6. vue中定時器的處理

(1)一進入頁面觸發(fā)定時器定時發(fā)起請求

mounted(){
    let _this = this;
    let timeInterval = 10000;//10s
    this.$nextTick(function(){
        _this.timer = setInterval(function(){
            // console.log(new Date())
            _this.reqRrendValue()

        },timeInterval)
        
    })
}

(2) 離開此標簽頁的時候,清除定時器,返回此標簽頁時再啟動

監(jiān)測 visibilitychange事件

mounted(){

    window.addEventListener("visibilitychange",()=>{
        // debugger;
        if(document.hidden){
            console.log("我暫時離開頁面了");
            clearInterval(_this.timer);
        }else{
            _this.timer = setInterval(function(){
                // console.log(new Date())
                _this.reqRrendValue()

            },timeInterval)
        }
        
   })
    
},

(3) 在可視區(qū)域時啟動定時器,不在時清除定時請求

let _this = this;
let timeInterval = 10*1000;//10s

// 由于我的定時器在一進入頁面的時候,不在可視區(qū)域內(nèi),所以不用啟動定時器,這塊存在無作用
//this.$nextTick(function(){
//     if(isElementInViewport(document.getElementsByClassName("trend")[0])){
//             _this.timer = setInterval(function(){
//                 console.log(11111)
//                 console.log(new Date())
//                 _this.reqRrendValue()

//             },timeInterval) 
//         }else{
//             console.log("不在可視區(qū)域,清除定時請求");
//             clearInterval(_this.timer);
//         }
    
// })

window.addEventListener("visibilitychange",() => {
    clearInterval(_this.timer);
    if(document.hidden){
        console.log("我暫時離開頁面了");
        clearInterval(_this.timer);
    }else{
       if(isElementInViewport(document.getElementsByClassName("trend")[0])){
            _this.timer = setInterval(function(){
                console.log(2222222)
                console.log(new Date())
                _this.reqRrendValue()

            },timeInterval) 
        }else{
            console.log("不在可視區(qū)域,清除定時請求");
            clearInterval(_this.timer);
        }
    }
})

//監(jiān)測滾動事件
window.addEventListener("scroll",() =>{
    clearInterval(_this.timer);
    console.log(isElementInViewport(document.getElementsByClassName("trend")[0]));
    if(isElementInViewport(document.getElementsByClassName("trend")[0])){
        _this.timer = setInterval(function(){
            console.log(333333)
            console.log(new Date())
            _this.reqRrendValue()

        },timeInterval) 
    }else{
        console.log("不在可視區(qū)域,清除定時請求");
        clearInterval(_this.timer);
    }
})

//元素是否在可視區(qū)域內(nèi)
function isElementInViewport (el, offset = 23) {
    const box = el.getBoundingClientRect(),
          top = (box.top >= -25),
          left = (box.left >= 0),
          bottom = (box.bottom <= (window.innerHeight || document.documentElement.clientHeight) + offset),
          right = (box.right <= (window.innerWidth || document.documentElement.clientWidth) + offset);

    return (top && bottom&& left  && right);
}

(4)定時器必須在組件生命周期的destory時清除。(必須)

  • 在本組件中寫的定時器
destroyed(){
    console.log("我已經(jīng)離開頁面了");
    clearInterval(this.timer);
},
  • 引入的js
//在mapLoad.js中:

var scrollIntervalStart,scrollInterval;

const mapLoad = {
    ....
}

export {mapLoad,scrollIntervalStart,scrollInterval}

//在map.vue中:

import {mapLoad,scrollIntervalStart,scrollInterval} from '@/common/mapLoad';

destroyed(){
    //清除地圖上的滾動定時
    console.log("我已經(jīng)離開頁面了");
    clearInterval(scrollIntervalStart);
    clearInterval(scrollInterval);
},

7.自定義指令

/**
 * 注冊一個全局自定義指令 v-focus
 */
Vue.directive('focus', {
    // 當綁定元素插入到 DOM 中。
    inserted: function (el) {
        // 聚焦元素
        el.focus()
    }
})
/**
 * 注冊一個全局自定義指令 v-ctrlq,按下ctrl+q時執(zhí)行操作
 * 
 */
Vue.directive('ctrlq', {
    bind:function(el,binding,vnode){
        function documentHandler (e) {
            if (e && e.keyCode==81 && e.ctrlKey){
                if (binding.expression) {
                    binding.value(e);
                }
            }
        }
        el.__ctrlq__ = documentHandler;
        document.addEventListener('keydown',documentHandler);
    },
    unbind:function(el,binding){
        document.removeEventListener('keydown',el.__ctrlq__);
        delete el.__ctrlq__;
    }
})

/**
 * 注冊一個全局自定義指令 v-clickoutside,在元素之外點擊時執(zhí)行函數(shù),如點擊旁邊收起下拉框
 * 
 */
Vue.directive('clickoutside',{
    bind:function (el, binding, vnode) {
        function documentHandler (e){
            if (el.contains(e.target)) {
                return false;
            }
            if (binding.expression) {
                binding.value(e);
            }
        }
        el.__vueClickOutside__ = documentHandler;
        document.addEventListener('click',documentHandler);
    },
    unbind: function (el, binding){
        document.removeEventListener('click',el.__vueClickOutside__);
        delete el.__vueClickOutside__;
    }
})

8.vue-router 的理解

vue本身起的項目一般為http://localhost:8080,也就是http://localhost:8080/index.html,我們的項目如果是簡單的vue單頁面應用的話,其本身就只有一個頁面——index.html。而路由頁就相當于加了幾個hash切換,通過js動態(tài)加載其他幾個頁面的,所以其其實是http://localhost:8080/index.html/#/indexhttp://localhost:8080/index.html/#/list。

同時在服務器上,真實的頁面也就只有index.html,所以使用vue-router的mode:history模式就有問題了(這個原理嘛。。。)官網(wǎng)上有處理辦法,后端要配合進行配置才可以。

(官網(wǎng)上)HTML5 History 模式
vue-router 默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,于是當 URL 改變時,頁面不會重新加載。
如果不想要很丑的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉(zhuǎn)而無須重新加載頁面。

const router = new VueRouter({
  mode: 'history',
  routes: [...]
 })

當你使用 history 模式時,URL 就像正常的 url,例如 http://yoursite.com/user/id,也好看!
不過這種模式要玩好,還需要后臺配置支持。因為我們的應用是個單頁客戶端應用,如果后臺沒有正確的配置,當用戶在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就不好看了。
所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態(tài)資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。
圖片名字也都需要小寫。

9.vue-router的守衛(wèi)

本項目中要求在未登錄之前,不能進入別的路由頁,所以設(shè)置全局鉤子:

const router = new Router({
    base:__dirname,
    routes:routes
})

router.beforeEach((to,from,next) => {
    if(to.meta.requireAuth){
        if(store.state.login.user){
            next()
        }else{
            next({path:'/index'})
            store.commit('LOGIN_BOX',true)
        }
    }else{
        next();
    }
})

官網(wǎng)上————導航守衛(wèi)

路由單個守衛(wèi):

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

組件內(nèi)的守衛(wèi)

const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染該組件的對應路由被 confirm 前調(diào)用
    // 不!能!獲取組件實例 `this`
    // 因為當守衛(wèi)執(zhí)行前,組件實例還沒被創(chuàng)建
  },
  beforeRouteUpdate (to, from, next) {
    // 在當前路由改變,但是該組件被復用時調(diào)用
    // 舉例來說,對于一個帶有動態(tài)參數(shù)的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時候,
    // 由于會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調(diào)用。
    // 可以訪問組件實例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 導航離開該組件的對應路由時調(diào)用
    // 可以訪問組件實例 `this`
  }
}

完整的導航解析流程

  • 導航被觸發(fā)。
  • 在失活的組件里調(diào)用離開守衛(wèi)。
  • 調(diào)用全局的 beforeEach 守衛(wèi)。
  • 在重用的組件里調(diào)用 beforeRouteUpdate 守衛(wèi) (2.2+)。
  • 在路由配置里調(diào)用 beforeEnter。
  • 解析異步路由組件。
  • 在被激活的組件里調(diào)用 beforeRouteEnter。
  • 調(diào)用全局的 beforeResolve 守衛(wèi) (2.5+)。
  • 導航被確認。
  • 調(diào)用全局的 afterEach 鉤子。
  • 觸發(fā) DOM 更新。
  • 用創(chuàng)建好的實例調(diào)用 beforeRouteEnter
  • 守衛(wèi)中傳給 next 的回調(diào)函數(shù)。

10.vue中獲取input的type

聚集時改變type:

<input type="text" ref="pwd" v-model="rgform.rgpwd" placeholder="請輸入密碼" @focus="changeType">

changeType(e){
    e.target.type = 'password';
},

//或者:
this.$refs.pwd.type

11.vue中實現(xiàn)密碼可見不可見

<input type="password" v-model="rgform.rgpwd" ref="rgspwd" placeholder="請輸入密碼" v-if="viewFlag">
<input type="text" v-model="rgform.rgpwd" ref="rgspwd" placeholder="請輸入密碼" v-else><i class="el-eye" @click="changeView"></i>

changeView(){
    this.viewFlag=false;
}

12.for循環(huán)上需要有key標志,標志唯一性,否則報warning。

<el-option  v-for="item in protalOptions" :label="item.name" :key="item.id" :value="item.id"></el-option>

13.vue中title圖標的添加

在webpack.dev.conf.js中:

 new HtmlWebpackPlugin({
  filename: 'index.html',
  template: 'index.html',
  inject: true,
  favicon:'./favicon.ico'
}),

同時生產(chǎn)環(huán)境中,在webpack.prod.conf.js中:

new HtmlWebpackPlugin({
  filename: config.build.index,
  template: 'index.html',
  inject: true,
  favicon: './favicon.ico',
  minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
    // more options:
    // https://github.com/kangax/html-minifier#options-quick-reference
  },

14.ie11中打開vue項目頁面一片空白

Vue2.0做的項目在IE11下面打開一片空白?

安裝 "babel-polyfill" 即可。
在入口main.js文件引入:import 'babel-polyfill'
在webpack.base.conf.js中,

module.exports = {
    entry: {
        app: ["babel-polyfill", "./src/main.js"]
    }
},

15.為何vue不支持IE8

https://blog.csdn.net/csdn_yudong/article/details/78332665
因為 Vue.js 使用了 IE8 不能模擬的 ECMAScript 5 特性。

但具體是哪些特性呢?

Object.defineProperty()
該方法允許精確添加或修改對象的屬性。一般情況下,我們?yōu)閷ο筇砑訉傩允峭ㄟ^賦值來創(chuàng)建并顯示在屬性枚舉中(for…in 或 Object.keys 方法),但這種方式添加的屬性值可以被改變,也可以被刪除。而使用 Object.defineProperty() 則允許改變這些額外細節(jié)的默認設(shè)置。例如,默認情況下,使用 Object.defineProperty()增加的屬性值是不可改變的。

16.vue的js中的動態(tài)html中的img的src寫法

只要在script中的都需要用require()的格式加載圖片

var contentHtml = `<div class="popWrap">
    <div class="popTop">
        <div class="imgBox">
            <img src=${require("@/images/portait.jpg")}>
        </div>
        <ul class="infoRight">
            <li><label>姓&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;名:</label><span>${cfeature.get('person_name')}</span>
            <div class="hrefs"><a title="到檔案" class="popArchives" data-card="${cfeature.get('person_card')}"></a>
            </div>
        </ul>
    </div>
    <div class="closePopup">
        <span>x</span>
    </div>
</div>`;
overlay.setPosition(undefined);
if(overlay.getPosition() == undefined){
    overlay.setPosition(cfeature.get('center'));
    map.getView().setCenter(cfeature.get('center'));
}

map.addOverlay(overlay);
$("#popup").html(contentHtml);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容