vue2實踐(持續更新)

記錄一些小技巧和踩過的坑html

因爲本篇文章內容太多,致使SF編輯器有點卡,因此新開闢了一篇 vue2實踐(二),後續再這裏更新。vue

1. props 帶不帶冒號的區別

<child1 ref="child1" msg="{name:'bill'}"></child1>
 
 <child1 ref="child1" :msg="{name:'bill'}"></child1>

首先冒號是v-bind的縮寫,不帶冒號後面是字符串,帶了冒號就是數據綁定,引號裏面的內容是變量或者表達式,
組件內不能修改props的值,同時修改的值也不會同步到組件外層,即調用組件方不知道組件內部當前的狀態是什麼react

vue 組件props傳遞時,爲何有時候須要加冒號,有時候不須要?
如何在Vue2中實現組件props雙向綁定webpack

2. computed屬性,能夠set,可是設置的是data返回的數據,不能設置自身。

若是計算屬性是對象的話,能夠設置他的屬性。git

3. 組件的生命週期函數是在template標籤裏的數據發生變化時候觸發update

數據可能更新了,可是沒有綁定到dom上面的話,不會調用update鉤子函數。github

4. 給變data的第二季屬性的值,data不會更新,致使組件不會更新

因此在這個時候應該用Object.assign()從新生成新的對象。第一級屬性值更新的話,data是更新的!web

5. 動態綁定style的話,後面的樣式值不能加分號

style = {
              color: "rgb(66, 180, 232)"
       };
  //下面渲染不出來
    style = {
              color: "rgb(66, 180, 232)";
       };

6. filter 過濾器

vue2.0 的時候把過濾器移除了,如今2.10又加了上去,vue-router

定義filter過濾器:
寫在實例Vue內部的是局部過濾器,vuex

new Vue({
  filters:{
  formatMoney: function (value){
      return "$"+value.toFixed(2);
   }
 }
})

寫在外部的是全局過濾器segmentfault

Vue.filter("money", function (vaule, type) {
    return "¥" + vaule.toFixed(2) + type;
})

組件內調用:

<span v-text="message | wrap 'before' 'after'"></span>//1.x的寫法,2直接wrap('before','after')調用
Vue.filter('wrap', function (value, begin, end) {
  return begin + value + end
})

補充下:一個豎線 | 在js中是二進制運算

想問一下這個用豎線分隔開是什麼意思

7. watch監測對象或者數組,不是替換對象或者數組,newVal和oldVal是同一個值。

注意:在變異(不是替換)對象或數組時,舊值將與新值相同,由於它們的引用指向同一個對象/數組。Vue 不會保留變異以前值的副本。

vm.$watch

8. 爲組件綁定原生事件

有時候,你可能想在某個組件的根元素上監聽一個原生事件。可使用 .native 修飾 v-on 。例如:

<my-component v-on:click.native="doTheThing"></my-component>

9. 2.1.6computed在beforeMount前面執行的,vue2.2.1恰好相反

10. v-for和v-if在同一個標籤使用的話,v-for的優先級高於v-if

若是在同一標籤使用,v-if就是用來過濾v-for裏面的數據的,先走if的話用template套在外面

今天並列使用的時候遇到的巨坑:

<topic v-for="(topic,idx) in topics" :model="topic" :showIdx="false" :clickHandler="handleTopicClick"  v-if="mode==0"/>
<school-topic v-for="t in topics" :model="t" :style="showStyle(t)" :clickHandler="handleTopicClick" v-else />

結果topics只有三條數據,可是渲染出9條數據,官網說的很清楚:v-for with v-if

11.keep-alive 緩存組件在內存中,再次進入該頁面不會從新渲染,用於保存頁面的原始狀態

<template>
    <div id="app">
        <keep-alive include="SelectTopics">
            <router-view></router-view>
        </keep-alive>
    </div>
</template>

即便設置了keep-alive組件的beforeUpdateupdated鉤子函數仍是會調用的。

activated和unactivated鉤子是在keep-alive組件裏面被調用的,不是第一次進入keep-alive組件的話,調用順序是:
beforeEach->beforeRouteEnter->activated->beforeUpdate->beforeRouteEnternext函數

也能夠在離開頁面的時候手動銷燬改組件:

beforeRouteLeave(to, from, next) {
    if (to.path === "/examcentre") {
        this.$destroy();
    }
    next();
 }
//或者
  deactivated: function () {
    console.log(4)
    this.$destroy();
  },

有時候根據需求(好比該組件是複用的)須要在再次進入該頁面的時候從新從後臺獲取數據,那麼能夠在activated鉤子函數中請求數據來update頁面。

vue.js 可否設置某個組件不被keep-alive?
vue2.0 keep-alive最佳實踐
Vue如何作到前進刷新數據,後退不刷新數據呢?
<keep-alive>組件緩存問題
Vue路由開啓keep-alive時的注意點
vue.js+vue-router+webpack keep-alive用法

瀏覽器的前進回退並不會走dom綁定的前進後退的事件

因此要想清除vuex state裏面的數據的話,能夠放在beforeRouteLeave裏面作處理。

this.$store.commit("SET_PAPERATTRIBUTE", {});

彈窗組件

mint-ui 中的Toast MessageBox Indicator 調用的方式是Toast('提示信息');或者在全局引入mint-ui而後再組件裏this.$toast("提示信息"),這種方式和咱們普通的引入組件的方式都不一樣,一般咱們是在模板裏直接將組件放到模板裏面,這就意味着父組件在render的時候,子組件也被render到了dom裏面:

<template>
    <div class="my-set-attr-wrap">
        <set-attribute ref="setMyAttr" :style="setAttrStyle" :model="attributeModel" />
    </div>
</template>

this.$toast("提示信息")這種是在函數中調用,確定也是要render到dom裏面的,改咋辦呢?查看了mint-ui的實現方式:document.body.appendChild(instance.$el);
目錄:

clipboard.png

TopicDetailPopup.vue文件就是普通的vue寫法,
index.js:

clipboard.png

這裏考慮到每次彈出層不能都去建立新的組件,咱們只須要將組件內的數據更新就能夠了,dom也不須要刪除,而後再建立,就用到了單例模式,這邊的instance是在父組件沒銷燬以前都是存在的,每次只是更新了組件的數據,爲啥沒被銷燬呢,這邊造成了一個閉包:
clipboard.png

調用:

import TopicDetailPopup from '../topicDetailPopup/index.js'
TopicDetailPopup.open({
                            detail: res.data
                     });

可是這個地方出現個問題this.$store如今爲undefined,應該是由於這個組件是直接new實例化的,而不是經過根組件嵌套的,
main.js

new Vue({
    router: router,
    store,
    render: h => h(App)
}).$mount("#app");

store註冊在根組件裏面,而彈窗組件沒有和根組件關聯,因此拿不到store。

要是能將彈窗組件插入其餘組件問題就能解決了,貌似如今API沒有提供這樣的接口,vue2動態添加組件的話能夠用render函數,能夠我如今的彈窗組件是模板的形式,也能夠動態插入到父組件,<component :is="componentId"></component>且須要在components裏面引用,這樣又回到了模板語法了。

彈窗的弊端:
vue-devtools 無法檢測到組件,也無法檢測到vuex,對於webapp來講返回鍵無法使用,關閉不了當前的彈窗,形成上面的問題都是因爲沒用使用router。
對於安卓手機返回鍵無法使用能夠採用曲線救國的方式,禁用返回鍵,js無法直接操做安卓返回鍵,可是可使用beforeRouteLeave,使得返回鍵沒有效果,

beforeRouteLeave(to, from, next) {
        if (this.popupVisible) {//彈窗顯示的話,路由無法跳轉
            next(false);
        } else {
            next(true);
        }
 }

彈窗的好處:
在當前頁面直接彈出,這樣能夠保存當前頁面的數據和滾動條的位置,還有就是組件複用的話,直接關閉彈窗,不須要根據不一樣的頁面去回退或者前進到特定的頁面。

使用的是vue2.0,如何動態添加組件。例如實現點擊A按鈕添加aTest組件,點擊B按鈕添加bTest組件。

:model和v-model的區別

v-model一般用於input的雙向數據綁定 <input v-model="parentMsg">,也能夠實現子組件到父組件數據的雙向數據綁定:
首先說說v-model的用法:
model.vue

<template>
    <div>
        父:
        <input type="text"
               v-model="msg">
        <child v-model="msg"></child>
    </div>
</template>
<script>
import child from './modelChild.vue'
export default {
    name: "model",
    props: {

    },
    components: {
        child
    },
    data() {
        return {
            msg: "ppp"
        }
    },
    methods: {

    }
}
</script>
<style lang="less">

</style>

modelChild.vue

<template>
    <div>
        子:
        <input type="text"
               @input="handleInput"
               class="text"
               :value="value">
    </div>
</template>
<script>
export default {
    name: "modelChild",
    props: ["value"],
    methods: {
        handleInput(e) {
            this.$emit("input", e.target.value)
        }
    }
}
</script>
<style lang="less">
.text {
    height: 20px;
    width: 200px;
}
</style>

不管改變父組件仍是子組件的輸入框,value和msg的值都會改變,兩個輸入框的值也就同時改變了。

:model和v-model的區別
:model是v-bind:model的縮寫,<child :model="msg"></child>這種只是將父組件的數據傳遞到了子組件,並無實現子組件和父組件數據的雙向綁定。固然引用類型除外,子組件改變引用類型的數據的話,父組件也會改變的。

Vue.component註冊全局組件

查看vue-router源碼的時候發現install.js裏面兩句:

Vue.component('router-view', View)
Vue.component('router-link', Link)

這兩句就是全局註冊了這兩個組件,

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)

clipboard.png

clipboard.png

這三步後,在組件裏直接使用 <router-view></router-view>而不用先import再使用。

在mint-ui裏也是相同的作法:
src/index.js

const install = function(Vue) {
  if (install.installed) return;
  Vue.component(Header.name, Header);//註冊全局組件
  Vue.component(Button.name, Button);
  Vue.use(InfiniteScroll);//使用指令插件
  Vue.use(Lazyload, {
    loading: require('./assets/loading-spin.svg'),
    try: 3
  });//使用指令插件或lazy-component
  Vue.$messagebox = Vue.prototype.$messagebox = MessageBox;
  Vue.$toast = Vue.prototype.$toast = Toast;
  Vue.$indicator = Vue.prototype.$indicator = Indicator;
};

後面的Vue.$toast = Vue.prototype.$toast = Toast;使得咱們能夠在組件中直接調用this.$toast("提示信息")

組件上寫class

clipboard.png

以前在寫react的時候是不能夠這麼作的,今天查看了popup.vue的時候發現vue是能夠這麼幹的,直接渲染到了組件的根元素上面。用在組件上

Boolean類型的props能夠直接定義:

clipboard.png

props: {
    fixed: Boolean,
    value: {}
  }

數據更新頁面沒刷新

今天在concat兩個數組的時候發現數據更新了,頁面並無刷新,debug看了下數據,concat的數據沒有get set屬性訪問器,致使後來push的數據也沒有屬性訪問器。以前沒有細看文檔。搜了下原來push是變異方法,concat不是。
解決辦法有二:

  • 使用變異方法

  • 使用vue component的$set函數
    看一些小夥伴的回答是data的$set方法,至少vue2是沒有的。具體可查看文檔列表渲染

個人解決辦法是:

Array.prototype.push.apply(arr, item);

render函數和模板語法只能二選一

今天在模板.vue文件里加入render函數發現並不會執行render函數,原來是vue-loader會將template轉成render函數,因此只能二選一。.vue文件如何使用render函數渲染組件

控制input只能輸入數字

<input type="number">在pc和手機端均可以實現只能輸入數字,但是手機端彈出的軟鍵盤裏面沒有完成或者搜索按鈕,搜了下,如今的HTML5 number的狀況下並無支持搜索按鈕,type='text'是有的。因此曲線救國,控制表單只能輸入數字。
起初的想法是先把在

<input type='text' @input="handleInput" :value="val"/>

handleInput(e){
this.val=e.target.value.replace(/[^\d]/g,'');
}

可是這種並不會實時刷新表單的數據,下面就會起做用

e.target.value=e.target.value.replace(/[^\d]/g,'');

優雅點的寫法,用自定義指令:

//<input type="text" v-number-only />
 directives: {
        numberOnly: {
            bind: function(el) {
                el.handler = function() {
                    el.value = el.value.replace(/\D+/, '')
                }
                el.addEventListener('input', el.handler)
            },
            unbind: function(el) {
                el.removeEventListener('input', el.handler)
            }
        }
    },

vue的input中,如何限制只能輸入number

彈出層彈出文本框獲取焦點

因爲彈出層是單例模式,因此打開彈出層只會執行一次mounted鉤子函數,我去監聽

visible(val) {
            if (val) {
                this.$refs.textbox.focus();//這樣並不能使文本框獲取焦點
            } else {
                this.detail = null;
                this.$refs.textbox.value = "";
            }
        }

解決辦法也是使用自定義指令

focus: {
            update(el) {
                el.focus();
            }
  }

vue如何實現點擊button 使input獲取焦點

改變v-html解析後臺返回的HTML樣式

平時在寫組件裏面的樣式加上scoped,避免樣式的全局污染,而從後臺返回的HTML無效的,解決辦法就是在組件裏再加一對style標籤,將樣式寫到這裏。

相關文章
相關標籤/搜索