vue學習記錄: 遇到過的問題記錄

書寫規範

  • prop 必須指定 type
{
    // ...
    props: {
      title: String,
      likes: Number,
      isPublished: Boolean,
      commentIds: Array,
      author: Object
    }
    //...
}

對於須要默認值的prop,建議指定其默認值javascript

項目構建

  • vue-cli 安裝中找不到vue命令

這是在ubuntu系統中遇到的,全局安裝後能夠css

npm install -g  vue-cli

圖片描述

Vue 組件間通訊

  • 父子 props/event $parent/$children ref provide/inject
  • 兄弟 bus vuex
  • 跨級 bus vuex provide.inject
跨層級的組件間通信可使用 eventbus
可是要注意兩點:
event 會註冊到全局,要注意模塊化
注意銷燬,否則會使用兩次
一、在vue中子組件爲什麼不能夠修改父組件傳遞的Prop, 若是修改了,二、Vue是如何監控到屬性的修改並給出警告的
  • 單向數據流,易於監測數據的流動,出現了錯誤能夠更加迅速的定位到錯誤發生位置

每當父組件屬性值修改時, 該值都將被覆蓋。
——> 引伸出一個問題:html

若是在子組件須要修改prop呢?
- 經過事件修改父組件狀態
- 或者子組件把prop賦給data()或者comuted,
  • 若是修改了:

Vue 是如何監控到屬性的修改並給出警告的前端

單向數據流

封裝Vue組件的一些技巧
vue 最先是雙向數據流,子組件能夠改變 props ,以後由於引起不少問題而改爲單向數據流。如今在子組件內觸發修改會致使報錯。
以函數透傳的形式實現控制子組件修改父組件狀態不是一個好辦法。vue

傳統實現仍是 v-modeljava

可是,v-model 裏子組件不能直接改變父組件狀態,而是要經過事件,本質上依然是單向數據流。react

webpack

https://vuejs-templates.githu...webpack

打包優化

優化vue項目打包速度(webpack)ios

懶加載(按需加載路由)

webpack 中提供了 require.ensure()來實現按需加載。之前引入路由是經過 import 這樣的方式引入,改成 const 定義的方式進行引入。git

  • 不進行頁面按需加載引入方式:
import  home   from '../../common/home.vue'
  • 進行頁面按需加載的引入方式:
const  home = r => require.ensure( [], () => r (require('../../common/home.vue')))

https://blog.csdn.net/qq_2762...

slot

slot 在ui庫中有普遍的應用

  • <slot></slot>標籤,簡單來講就是佔位符,它會幫你佔好位置,等你須要的時候直接將html傳入,它會幫你顯示出來。
  • 也有人說:props能夠將數據從父組件傳入子組件,slot能夠將html從父組件傳入子組件。那麼如何實現呢?

單個插槽:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="vue.min.js"></script>
    </head>
    <body>
        <div id="app">
            <h1>我是父組件的標題</h1>
            <my-component>
                <p>這是一些初始內容</p>
                <p>這是更多的初始內容</p>
            </my-component>
        </div>
        <script type="text/javascript">
            Vue.component('my-component', {
              // 有效,由於是在正確的做用域內
              template: '<div>\
                            <h2>我是子組件的標題</h2>\
                            <slot>只有在沒有要分發的內容時纔會顯示。</slot>\
                        </div>',
              data: function () {
                return {
                  
                }
              }
            });
            new Vue({
                el:'#app',
                data:{
                    msg:'你好啊'
                }
            })

        </script>
    </body>
</html>

組件中的模板中寫入slot標籤,在父級調用子組件的時候傳入html便可。

具名插槽

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="vue.min.js"></script>
    </head>
    <body>
        <div id="app">
            <my-component>
                  <h1 slot="header">這裏多是一個頁面標題</h1>

                  <p>主要內容的一個段落。</p>
                  <p>另外一個主要段落。</p>

                  <p slot="footer">這裏有一些聯繫信息</p>
            </my-component>
        </div>
        <script type="text/javascript">
            Vue.component('my-component', {
              // 有效,由於是在正確的做用域內
              template: '<div class="container">\
                          <header>\
                            <slot name="header"></slot>\
                          </header>\
                           <main>\
                            <slot></slot>\
                          </main>\
                          <footer>\
                            <slot name="footer"></slot>\
                          </footer>\
                        </div>',
              data: function () {
                return {
                  
                }
              }
            });
            new Vue({
                el:'#app',
                data:{
                    msg:'你好啊'
                }
            })

        </script>
    </body>
</html>

具名插槽,顧名思義當有多個slot標籤時,你須要給他們起個本身的名字,在父組件調用時須要slot="內部的對應名字",當存在沒有命名的slot標籤時,父級組件傳入的默認html代碼將所有輸出在無名的slot標籤中。

做用域插槽

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="vue.min.js"></script>
    </head>
    <body>
        <div id="app">
             <!-- 在父級中,具備特殊特性 slot-scope 的 <template> 元素必須存在,表示它是做用域插槽的模板。slot-scope 的值將被用做一個臨時變量名,此變量接收從子組件傳遞過來的 prop 對象: -->
             <child>
                <template scope="props">
                  <span>hello from parent</span><br>
                  <span>{{ props.text }}</span>
                </template>
            </child>
        </div>
        <script type="text/javascript">
            // 在子組件中,只需將數據傳遞到插槽,就像你將 prop 傳遞給組件同樣:
            Vue.component('child',{
               template:'<ul>' +
                            '<slot text="hello from child"></slot>' +
                         '</ul>',
                data:function(){
                  return {

                  }
                },
            });
            new Vue({
                el:'#app',
                data:{
                    msg:'你好啊'
                }
            })

        </script>
    </body>
</html>

https://codepen.io/AlexZ33/pe...

做用域插槽是一種特殊類型的插槽,用做一個 (能被傳遞數據的) 可重用模板,來代替已經渲染好的元素。
其實就是至關於,在父組件中能夠獲取到子組件傳遞出來的props對象,從而渲染到父組件上。

watch

Vue開發——watch監聽數組、對象、變量
這裏要注意的是對數組的watch

clipboard.png
vue——數組的深度監聽

組件 v-if 和 v-show 切換時生命週期鉤子的執行

v-if
初始渲染
初始值爲 false 組件不會渲染,生命週期鉤子不會執行,v-if 的渲染是惰性的。
初始值爲 true 時,組件會進行渲染,並依次執行 beforeCreate,created,beforeMount,mounted 鉤子。
切換
false => true
依次執行 beforeCreate,created,beforeMount,mounted 鉤子。
true => false
依次執行 beforeDestroy,destroyed 鉤子。
v-show
渲染
不管初始狀態,組件都會渲染,依次執行 beforeCreate,created,beforeMount,mounted 鉤子,v-show 的渲染是非惰性的。
切換
對生命週期鉤子無影響,切換時組件始終保持在 mounted 鉤子。

指令

v-cloak

vue v-cloak 解決頁面加載時閃爍出現vue標籤或者指令的問題

自定義指令

v-WaterMark

// chart/WaterMark.js
export default class WaterMark {
  constructor (userNm, userCd) {
    this.userNm = userNm
    this.userCd = userCd
  }
  draw () {
    let canvas = document.createElement('canvas')
    let ctx = canvas.getContext('2d')
    canvas.width = 250
    canvas.height = 130
    ctx.translate(canvas.width / 2, canvas.height / 2 - 35)
    ctx.rotate(-Math.PI / 12)
    ctx.font = '700 12px/Mircosoft Yahei'
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'
    ctx.fillStyle = '#eaf0f5'
    // ctx.fillStyle = '#f00'
    ctx.fillText(`鏡心的小樹屋 ${this.userNm} ${this.userCd}`, 0, 0)
    return canvas.toDataURL('image/png')
  }
}
// rule.js
/**
 * 用戶信息相關
 */
exports.useInfor = {
  data: {
    name: '',
    userCd: '',
    userNm: ''
  },
  clear: function () {
    this.data = {
      name: '',
      userCd: '',
      userNm: '',
      flag: false
    }
  }
}
// directives/WaterMark.js
import WaterMark from '../chart/WaterMark.js'
import { useInfor } from '../rule'

export default {
  inserted (el, binding) {
    let timer = setInterval(() => {
      if (useInfor.data.userNm && useInfor.data.userCd) {
        let wMark = new WaterMark(useInfor.data.userNm, useInfor.data.userCd)
        let imageSrc = wMark.draw()
        if (binding.value && binding.value === false) return
        el.style.background = `#fff url(${imageSrc}) repeat top left`
        clearInterval(timer)
      }
    }, 50)
  }
}

clipboard.png

v-check

v-focus

// https://cn.vuejs.org/v2/guide/custom-directive.html#%E9%92%A9%E5%AD%90%E5%87%BD%E6%95%B0
// 註冊一個全局自定義指令 'v-focus'
export default {
  // 當被綁定的元素插入到 DOM 中時……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
}

路由之間跳轉

  • 聲明式(標籤跳轉)
  • 編程式( js 跳轉) router.push('index')

clipboard.png

頁面刷新

最近遇到一個需求,須要刷新當前頁面來更新數據
vue 無痕刷新

組件局部刷新

【BUG】iview多選框插件默認選中有問題,局部刷新後會取消選中狀態?

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

[Vue warn]: Invalid prop: type check failed for prop "value". Expected String, Number, got Undefined. Vue出現該錯誤的解決辦法

https://www.cnblogs.com/sifo/...

iview樣式修改不生效

在使用vue框架iview是常常須要在組件裏面修改某一個樣式,爲了防止組件之間的樣式污染,咱們須要使用scoped來限制在當前組件內生效,但每每樣式會沒法生效。我以前的解決方案是在當前這個組件的父級加一個只有當前組件纔有的class而後早style沒有scoped中去寫樣式,這樣既能夠改變iview自帶的樣式,也能夠人爲去限制組件之間的樣式污染,這也是當時沒有辦法下本身想到的惟一的辦法。最近又發現一個新的解決方案/deep/深度選擇器 ->戳這裏

clipboard.png

.reset-sub-modal /deep/ .ivu-modal-footer
    padding-bottom: 25px

clipboard.png

生命週期

圖片描述

https://www.cnblogs.com/golov...

vue中的dom異步更新及$nextTick()

clipboard.png

一、dom異步更新的原理

觀察到數據變化,vue開啓一個隊列,並緩衝同一事件循環的全部數據變化;
若是同一個watcher被屢次觸發,只會被推入隊列中一次;(去重,避免沒必要要計算和DOM操做)
在下一個事件循環tick中,vue刷新隊列並執行已去重的工做;

二、vue.nextTick()

所以,改數據(eg vm.someData = ’88’)時,組件不會立刻更新,而是在vue下一個tick刷新隊列時更新;
爲了在數據變化後,要在vue的dom狀態更新後作什麼,可在數據變化後調用vue.nextTick(callback),則dom更新完成後會調用回調函數;

三、nextTick的使用場景

Vue生命週期的created()鉤子函數進行的DOM操做必定要放在Vue.nextTick()的回調函數中;
在數據變化後要執行的某個操做,而這個操做須要使用隨數據改變而改變的DOM結構的時候,這個操做都應該放進Vue.nextTick()的回調函數中;

更多原理和示例戳這裏

內置組件component

文檔
簡單示例: https://jsfiddle.net/chrisvfr...

正常項目中:

clipboard.png

clipboard.png

clipboard.png

clipboard.png

.sync

對於VUE的初學者來說,確定會感受prop的寫法很麻煩,很討厭!你確定想若是prop也能夠實現雙向綁定那怎是一個爽字了得!不過現實是殘酷的,若是子組件能夠任意修改父組件的內容,那勢必會帶來數據的混亂,從而形成維護的困擾!畢竟父組件也是有尊嚴的!

https://www.jianshu.com/p/d42...

觸發其餘組件方法

使用 Vue.js 怎麼調用其餘組件的方法
中央事件總線eventbus

clipboard.png

/**
 * 中央事件總線
 * 這個插件能夠在能夠在全部的組件之間隨意使用 
 * 經常使用於兄弟組件間通訊
 * 注意:
 * $bus.on應該在 created鉤子內使用,若是在mounted使用,它可能接受不到其餘組件來自created鉤子發出的事件       
 * 第二點是使用了$bus.on,在beforeDestroy鉤子裏應該使用$bus.off解除,由於組件銷燬後,就不必把監聽的句柄儲存在vue-bus裏了
 * @param {*} Vue 傳入的Vue class
 */
const install = function (Vue) {
  const Bus = new Vue ({
    methods: {
      emit (event, ...args) {
        this.$emit(event, ...args)
      },
      on (event, callback) {
        this.$on(event, callback)            
      },
      off (event, callback) {
        this.$off(event, callback)
      }
    }
  })
  Vue.prototype.$bus = Bus
}

export default install

屢次觸發問題-> issue

經常使用組件

資料集合
multiselect
在 vue-multiselect 基礎上建立 ImageSelect 組件
https://github.com/vuejs/awes...

組件封裝

封裝Vue組件的一些技巧

webpack打包速度優化

個人知乎專欄

實現label-required

clipboard.png

.label-required
    display: inline-block
    height: 33px
    line-height: 28px
    &:before
      content: '*'
      display: inline-block
      margin-right: 4px
      line-height: 1
      font-family: SimSun
      font-size: 12px
      color: #ed3f14

$parent

$parent 也能夠用來訪問父組件的數據。

並且子組件能夠經過$parent 來直接修改父組件的數據,不會報錯!

可使用props的時候,儘可能使用props顯式地傳遞數據(能夠很清楚很快速地看出子組件引用了父組件的哪些數據)。

另外在一方面,直接在子組件中修改父組件的數據是很糟糕的作法,props單向數據流就沒有這種顧慮了。

禁止直接更改組件上的class樣式 ,用自定義class覆蓋

clipboard.png

clipboard.png

clipboard.png

自動化部署

非大廠隔離環境的話可用ssh( 大廠生產環境是隔離的 要經過跳板機 代碼不可能經過ssh直接發到生產的):
Vue-CLI 3.x 自動部署項目至服務器

常見問題

組件中 data 爲何是函數

爲何組件中的 data 必須是一個函數,而後 return 一個對象,而 new Vue 實例裏,data 能夠直接是一個對象?

由於組件是用來複用的,JS 裏對象是引用關係,這樣做用域沒有隔離;而 new Vue 的實例,是不會被複用的,所以不存在引用對象的問題。

v-model原理解析

從最初學習Vue就知道v-model能夠實現雙數據綁定,但它能實現綁定的原理究竟是什麼呢?經過查看官方文檔和各類博客資料,如下是個人理解。

根據官方文檔介紹,v-model本質上就是語法糖,即利用v-model綁定數據後,其實就是既綁定了數據,又添加了一個input事件監聽,以下:
https://www.cnblogs.com/attac...

雙向綁定原理

這個問題幾乎是面試必問的,回答也是有深有淺。基本上要知道核心的 API 是經過 Object.defineProperty() 來劫持各個屬性的setter / getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調,這也是爲何 Vue.js 2.x 不支持 IE8 的緣由(IE 8 不支持此 API,且沒法經過 polyfill 實現)
https://cn.vuejs.org/v2/guide...

vue.js 是採用數據劫持結合發佈者-訂閱者模式的方式,經過 Object.defineProperty()來劫持各個屬性的 setter,getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。

具體步驟:
第一步:須要 observe 的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter 和 getter 這樣的話,給這個對象的某個值賦值,就會觸發 setter,那麼就能監聽到了數據變化

第二步:compile 解析模板指令,將模板中的變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,更新視圖

第三步:Watcher 訂閱者是 Observer 和 Compile 之間通訊的橋樑,主要作的事情是:

  • 在自身實例化時往屬性訂閱器(dep)裏面添加本身
  • 自身必須有一個 update()方法
  • 待屬性變更 dep.notice()通知時,能調用自身的 update() 方法,並觸發 Compile 中綁定的回調,則功成身退。

第四步:MVVM 做爲數據綁定的入口,整合 Observer、Compile 和 Watcher 三者,經過 Observer 來監聽本身的 model 數據變化,經過 Compile 來解析編譯模板指令,最終利用 Watcher 搭起 Observer 和 Compile 之間的通訊橋樑,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據 model 變動的雙向綁定效果。

vue組件中各方法執行順序是怎麼樣的

vue組件中各方法執行順序是怎麼樣的

Props -》 Methods -》 Data -》Computed -》 Watch

clipboard.png

clipboard.png

長列表性能優化

咱們應該都知道vue會經過object.defineProperty對數據進行劫持,來實現視圖響應數據的變化,然而有些時候咱們的組件就是純粹的數據展現,不會有任何改變,咱們就不須要vue來劫持咱們的數據,在大量數據展現的狀況下,這可以很明顯的減小組件初始化的時間,那如何禁止vue劫持咱們的數據呢?能夠經過object.freeze方法來凍結一個對象,一旦被凍結的對象就不再能被修改了。

export default {
  data: () => ({
    users: {}
  }),
  async created() {
    const users = await axios.get("/api/users");
    this.users = Object.freeze(users);
  }
};

另外須要說明的是,這裏只是凍結了users的值,引用不會被凍結,當咱們須要reactive數據的時候,咱們能夠從新給users賦值。

export default {
  data: () => ({
    users: []
  }),
  async created() {
    const users = await axios.get("/api/users");
    this.users = Object.freeze(users);
  },
  methods:{
    // 改變值不會觸發視圖響應
    this.users[0] = newValue
    // 改變引用依然會觸發視圖響應
    this.users = newArray
  }
};

vue-router

vue-router 有哪幾種導航鉤子?
  • 全局導航鉤子
  • router.beforeEach(to, from, next),
  • router.beforeResolve(to, from, next),
  • router.afterEach(to, from ,next)
  • 組件內鉤子
  • beforeRouteEnter,
  • beforeRouteUpdate,
  • beforeRouteLeave
  • 單獨路由獨享組件
  • beforeEnter
import NProgress from 'nprogress'
// http://ricostacruz.com/nprogress/

clipboard.png

vue 中 ajax 請求代碼應該寫在組件的 methods 中仍是 vuex 的 action 中?

若是請求來的數據不是要被其餘組件公用,僅僅在請求的組件內使用,就不須要放入 vuex 的 state 裏

若是被其餘地方複用,請將請求放入 action 裏,方便複用,幷包裝成 promise 返回

clipboard.png

組件開發

組件要考慮的三個基本內容:

  • 交互
  • 樣式
  • 內容

組件須要提供修改樣式的能力, 修改內容的能力,和基本的交互反饋能力。

而一個可複用的組件,須要開放控制粒度。一般來講,控制粒度約高的組件,開發者使用起來就越方便,可是維護起來也越困難。肯定本身的組件控制開放到什麼程度是重要的內容。

另外,也存在只提供基本的控制開放的組件。各我的會有其偏向性。而反饋組件的狀態決定了組件是否易用。程序須要知道用戶作了什麼。

恰當的反饋,加上合適的控制,才能寫出易用的組件。

封裝組件

封裝Vue組件的一些技巧

代碼規範

vue 風格指南

工程實踐

Vue 項目架構設計與工程化實踐

參考

vue中的css做用域、vue中的scoped坑點
css loader 深度做用選擇器
vue nextTick深刻理解-vue性能優化、DOM更新時機、事件循環機制
Vue.js 技術揭祕
Vue技術內幕
深度剖析:如何實現一個 Virtual DOM 算法
Vue使用中的小技巧
Vue問得最多的面試題
讓vue-cli3.0 配置簡單起來(vue.config.js編結)
Creating Vue.js Component Instances Programmatically
Vue項目經驗
「Vue實踐」武裝你的前端項目
7個有用的Vue開發技巧
基於vue的進階散點乾貨

相關文章
相關標籤/搜索