vue-cli 實戰總結

Christine發表於2017-11-27

vue-cli 實戰總結
每天不定時更新!!!!請新增關注哦!!!(最後更新日期:2019,03,04)

也可能是因為接觸vue時間也不長,經常落入不知名的‘坑’中,對於我這個菜鳥來說,每次‘落坑’無疑是一場不小的災難。前兩天有個朋友在問我,在使用vue中有沒有遇到一些很難解決的問題,一下我也只能說出一兩個,正所謂‘光說不練,假把式’,所以索性就抽時間總結一下我在專案中遇到的vue的問題,也貼出了效果圖片,這樣看起來也比較清晰。有寫的不對的地方,在您時間還允許的情況下,還勞煩大家告訴我哦,我也好儘早修改,以免給看文章的其他同仁帶來不必要的麻煩!(當前版本:"vue@2.5.3") -------------------在此謝過!-----------

說到vue的實戰,不得不說vue專案建立,那麼關於vue cli專案搭建,我在之前的文章中有專門寫過,有不懂的同學,可參考我的第一篇文章: vue cli 框架搭建

  • 接下來給大家安利一個vue的網頁執行工具 iVuewRun網頁版的vue,可直接執行使用,還可以分享給小夥伴!


先陳列一下vue的整體架構:

事件:methods:{  };

過濾器:filters:{  };

自定義指令:directive:{  };

模版:components:{  };

計算:conputed:{  };

觀察者:watch:{  };

鉤子函式:

    created:function(){
      //建立  
    },
    mounted:function(){ 
      //掛載
    },
    updated:function(){
      //更新  
    },
    destoryed:function(){
     // 銷燬 
    }
複製程式碼

一、用不同的方式新增css

vue的每個元件中,都可以自定義cssjs,那麼如果只希望當前的css只在當前頁面生效,可以在style 的標籤這樣書寫,這樣當前頁面的所有css樣式,除當前元件,不會在其他元件生效並且不會影響到其他元件頁面渲染。

<style scoped> </style>
複製程式碼

如果你引入來sass到vue專案中,那麼只需在當前元件新增lang屬性即可:

sass $

<style scoped lang="scss"> </style>
複製程式碼

亦你的專案引入的不是sass,是less,也是同樣更改lang屬性即可:

less @:

<style scoped lang="less"> </style>

複製程式碼

動態傳入style值的幾種方式:


1.正常class樣式:

<template>
<div>
    <p class="fs20">1.正常class樣式: 2018年8月27日</p>
</div>
<template>

<style>
    .fs20 {
        font-size: 20px
    }
</style>
複製程式碼

頁面展現:

vue-cli 實戰總結


對於多個"../../../"查詢引入檔案時,可以先跳到最外層,即src層開始查詢

關於引入外部的less檔案或者img圖片:

~@/xxx/...
複製程式碼

vue-cli 實戰總結
關於引入外部js、template、component:

@/xxx/...
複製程式碼

2.根據data中的className對應的class,可用於動態切換class:

<template>
<div>
    <p :class="className">2.動態切換class的值</p>
</div>
<template>
<script>
    export default {
        data() {
            return {
                className: "classA"
            }
        },
        components: {},
        mounted() {},
        methods: {},
        watch: {}
    }
</script>

<style>
    .classA {
        color: yellowgreen
    }
</style>
複製程式碼

頁面展示:

vue-cli 實戰總結


3.給當前的class新增判斷:當isOktrue時新增class,為false時不新增:

<template>
<div>
    <p :class="{colorRed:isOk}">
        3.新增判斷:當isOk為true是新增class,為false時不新增
    </p>
    <Checkbox v-model="isOk">Checkbox</Checkbox>
</div>
<template>
<script>
    export default {
        data() {
            return {
                isOk: true,
            }
        },
        components: {},
        mounted() {},
        methods: {},
        watch: {}
    }
</script>

<style>
   .colorRed {
        color: red
    }
</style>
複製程式碼

頁面展示:

vue-cli 實戰總結

vue-cli 實戰總結


4.以陣列的方式,一次新增多個class:

<template>
<div>
    <p :class="[classC,classD]">4.以陣列的方式,一次新增多個class</p>
</div>
<template>
<script>
    export default {
        data() {
            return {
                classC: "classC",
                classD: "classD"
            }
        },
        components: {},
        mounted() {},
        methods: {},
        watch: {}
    }
</script>

<style>
 .classC {
        font-size: 16px;
        font-weight: 600;
    }
    .classD {
        color: blue
    }
</style>
複製程式碼

頁面展示:

vue-cli 實戰總結


5.使用三元運算子判斷切換class樣式,當isOktrue時用的是classA,當為false的時候用的是classB:

<template>
<div>
    <p :class="isOk?classA:classB">5.使用三元運算子判斷切換class樣式</p>
</div>
<template>
<script>
    export default {
        data() {
            return {
                isOk: true,
                classA: "classA",
                classB: "classB"
            }
        },
        components: {},
        mounted() {},
        methods: {},
        watch: {}
    }
</script>

<style>
   .classA {
        color: yellowgreen
    }
    .classB {
        color: green
    }
</style>
複製程式碼

頁面展示:

vue-cli 實戰總結

vue-cli 實戰總結

6.繫結動態的style的樣式:

<template>
<div>
    <p :style="{color:color,fontSize:font}">6.繫結style的樣式</p>
</div>
<template>
<script>
    export default {
        data() {
            return {
                color: "red",
                font: "18px",
            }
        },
        components: {},
        mounted() {},
        methods: {},
        watch: {}
    }
</script>

<style>
 
</style>
複製程式碼

頁面展示:

vue-cli 實戰總結

7.給style 繫結物件:

<template>
<div>
    <p :style="styleObject">7.給style 繫結物件</p>
</div>
<template>
<script>
    export default {
        data() {
            return {
             styleObject:{
                color:"pink",
                fontWeight:"600"
            }
        },
        components: {},
        mounted() {},
        methods: {},
        watch: {}
    }
</script>

<style>
 
</style>

複製程式碼

頁面展現:

vue-cli 實戰總結

二、關於迴圈中的imgsrc賦值的問題

vue中的迴圈是使用v-for 來實現的,在標籤中注入v-for,在接下來使用到的地方就可以直接使用。

<template>

    <div  v-for="item in cityList">

        <div>城市名稱:{{item.title}}</div>

        <div>城市ID:{{item.id}}</div>

        <div>城市圖片:<img src={{item.img}}></div>  //這行是報錯的

    </div>

</template>

<script>
     export default:{
         data(){
            return:{
                cityList:[{
                   title:'北京',
                        id:001,
                        img:'static/logo.png'
             },
             {
                   title:'上海',
                        id:002,
                        img:'static/logo.png'
             }]
         }
        }
    }

</script>
複製程式碼

報錯如下:(這裡意思是在“src”屬性插值將導致404請求。使用v-bind:src 簡寫為:src 代替)

[HMR] bundle has 1 errors
client.js?d90c:161 ./~/_vue-loader@12.2.2@vue-loader/lib/template-compiler?{"id":"data-v-60d18b79","hasScoped":true,"transformToRequire":{"video":"src","source":"src","img":"src","image":"xlink:href"}}!./~/_vue-loader@12.2.2@vue-loader/lib/selector.js?type=template&index=0!./src/components/vuetest.vue
(Emitted value instead of an instance of Error) 
  Error compiling template:
  
  <div>
     <h1>vue測試頁面</h1>
     
       <div  v-for="item in cityList">
  
            <div>城市名稱:{{item.title}}</div>
  
            <div>城市ID:{{item.id}}</div>
  
            <div>城市圖片:<img src="https://user-gold-cdn.xitu.io/2017/11/26/15ff7324b8313b05"></div>  
  
     </div>
  </div>
  
  - src="https://user-gold-cdn.xitu.io/2017/11/26/15ff7324b8313b05": Interpolation inside attributes has been removed. Use v-bind or the colon shorthand instead. For example, instead of <div id="{{ val }}">, use <div :id="val">.

 @ ./src/components/vuetest.vue 10:2-340
 @ ./src/router/index.js
 @ ./src/main.js
 @ multi ./build/dev-client ./src/main.js

複製程式碼

因為vue官網在介紹v-bind時,不可以再使用{{}},例如href的兩種使用:

<template>
    <div>
        <a :href='msg'>獲取動態資料</a> 
        <a href='http://www.baidu.com'>百度</a> 
    </div>    
</template>
<script>
   export default:{
        data(){
          return:{
            msg:'http://www.baidu.com'
          }  
       }

}
</script>

複製程式碼

正確程式碼如下:

<template>

    <div  v-for="item in cityList">

        <div>城市名稱:{{item.title}}</div>

        <div>城市ID:{{item.id}}</div>

        <div>城市圖片:<img :src='item.img'></div>  

    </div>

</template>

<script>
     export default:{
         data(){
            return:{
                cityList:[{
                   title:'北京',
                        id:001,
                        img:'static/logo.png'
             },
             {
                   title:'上海',
                        id:002,
                        img:'static/logo.png'
             }]
         }
        }
    }
</script>
複製程式碼

vue-cli 實戰總結

三、關於v-ifv-show的區別

在vue中有兩種隱藏元素的方式,那就是 v-ifv-show,但是兩者有什麼區別呢?什麼時候用v-if,什麼時候用v-show呢?

  • 1.先說最大的區別,`v-if` 通過條件判斷來渲染條件塊,當為假值時,當前條件塊的所有`DOM`元素不進行渲染;`v-show`同樣也是條件判斷,但如果`v-show`的值為假值時,當前條件塊雖不會在頁面顯示,但已經渲染完畢,只是屬性設定成了`display:none`.總結就是`v-if` 是通過條件判斷來新增和刪除`DOM`元素。`v-show`是通過`display:block`和`display:none`來控制元素的顯示隱藏。
  • 2.`v-if` 是有惰性的,如果初始條件為假值,則直接什麼也不做,只有在條件變為真時才開始區域性編譯;`v-show`是在任何條件都被編譯,然後被快取,而且`DOM`元素保留,即使為假值時,在後臺仍然可以看到`DOM`元素已經被渲染出來。
  • 3.`v-if`適合在條件不太可能變化時使用,v-show適合頻繁切換。
  • 4.`v-if`後面可以跟`v-else`,或`v-else-if`,但`v-show`不可以

    v-ifv-show兩個值都為true時的渲染結果,都正常渲染

    vue-cli 實戰總結
    v-ifv-show的值都為假值時:頁面沒有渲染,v-if未渲染dom元素,v-show渲染成功,但被新增了styledisplay:none

    vue-cli 實戰總結

    四、關於在vue中如何操作DOM元素。

    我們都知道vue框架中我們一般操作的都是資料,那麼假如我們要操作dom元素使用什麼方法呢?下面就來介紹一下!

    假如有以下元素,我們要獲取這個h2元素的文字,需要給此元素新增ref屬性,並賦予名字。

    <h2 ref='foo'>我是ref的值</h2>
    複製程式碼

    接下來就可以使用這個方法獲取到它的文字(注意是this.$refs不是this.$ref):

    console.log(this.$refs.foo.innerHTML')
    複製程式碼

    vue-cli 實戰總結
    那麼如何改變h2中的文字呢?

    this.$refs.foo.innerHTML='我是新值
    複製程式碼

    vue-cli 實戰總結


    這樣就可以和以前一樣,輕鬆的操作dom元素了,但是vue還是以運算元據為核心,所以建議儘量少的使用以上方法。

    五、探究router-link中的tag屬性。

    vue路由的router-link標籤中有一個屬性tag,是我今天在查閱資料時發現的,感覺比較有意思,推薦給大家。

    那麼我們就給<router-link to='/about'>的標籤上新增上tag屬性,並賦值:

    <router-link to='/fenceCenter' >中心點</router-link>
    <router-link to='/vuetest'tag='li'>vue測試</router-link>
    複製程式碼

    那麼我們看看它和我們正常渲染的有什麼不同


    vue-cli 實戰總結


  • 上面的是我們正常渲染的 vue會自動解析成``標籤的形式;
  • 下面是我們加了`tag`屬性的渲染成了賦值的`
  • `標籤。

    是不是很神奇呢? tag除了可以賦值li,還可以賦值成你想要的所有的標籤哦! p,span,h1,div....都可以哦!快去動手試試吧!!


    六、vue中的指定路由跳轉router

    在我們的實際業務中,有時需要在某一元件內,點選一個按鈕或者是點選一個連結切換跳轉到其他元件,也就是跳轉路由,我們可以試試下面的方法:

    //直接跳轉
    this.$router.push('/map')
    
    //條件允許時跳轉
    if(this.data){
        this.$router.push('/map')
    }
    複製程式碼

    注意:router需要掛在到vue例項上,這樣才可以獲取到this.$router,而且push後面的括號中的路由地址,也需要在vuerouter中有註冊,最後,在('')中填寫你需要跳轉的路由即可完成跳轉。

    七、vue的路由router中的go方法

    上面剛剛有講到路由router,接下來再講一個和router相關的方法go,這個方法是用作前進後退導航來使用的,有時實際業務需要我們新增一個返回上一頁面的功能,那麼我們就可以用go來實現。當為‘-1’時就可以後退到上一個路由頁面。

    this.$router.go('-1')
    複製程式碼

    八、輕鬆編寫vue元件

    vue是一個單頁面應用,那麼就會涉及到元件的問題,例如A頁面為一個主頁面,A1,A2,A3為3個子頁面,A1,A2,A3頁面的內容分別比較複雜,需要單頁面來編輯,這時我們就需要把A1,A2,A3寫成3個元件,然後全部載入A的主頁面上;又或有這樣的情況,當子頁面的複用率比較高時,同樣可以採取使用元件的方式來實現。總之,你可以把你想實現的寫成元件,這樣第一方便修改,第二頁面乾淨整潔,第三;讓別人看起來一目瞭然。 下面我們就看看,元件到底是怎麼實現吧!!!

    A頁面:

    <template>
      <div>
        <h2 style="color:red">我是主頁面</h2> 
        <content><content>      //我是新增的元件
      </div>
    </template>
    
    <script>
    import content from './content'    //找到元件的位置,引入
      export default {
        name: "",
        data() {
            return {
            }
        },
       components:{
          content      //將元件寫入模板內才可生效,當有多個元件,看用逗號分開
       },
        mounted() {
        },
        methods: {}
      }
    </script>
    
    <style scoped>
    </style>
    複製程式碼

    A頁面的子頁面(content元件頁面): 元件頁面就是普通頁面,當然元件頁面的事件也是會帶到主頁面的。

    <template>
    
      <div @click="foo()">我是元件頁面</div>
      
    </template>
    <script>
      export default {
        name: "",
        data() {
          return {
          }
        },
        mounted() {
        },
        methods: {
            foo(){
                alert("我是好人")
            }
        }
      }
    </script>
    
    <style scoped>
    </style>
    複製程式碼

    這時我們來看一下效果:


    vue-cli 實戰總結


    這樣你想要的效果就有了哦!

    那麼還需要注意一點:如果你的元件名字是駝峰式寫法,那麼按照以下方式修改:

    <template>
    
      <div>我是主頁面<content-f> </content-f>   //這裡要這樣寫</div>
      
    </template>
    <script>
    import contentF from './contentF'         //找到元件的位置 引入
      export default {
        name: "",
        data() {
            return {
            }
        },
       components:{
          contentF     //將元件寫入模板內才可生效,當有多個元件,看用逗號分開
       },
        mounted() {
        },
        methods: {}
      }
    </script>
    
    <style scoped>
    </style>
    
    複製程式碼

    九、在vue中觀察者watch的用法

    vue的官網是這麼介紹的:把它命名為 觀察者模式 雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的 watcher。這是為什麼vue通過watch。 選項提供一個更通用的方法,來響應資料的變化。當你想要在資料變化響應時,執行非同步操作或開銷較大的操作,這是很有用的。 通俗點講,就是在vue中有一個watch,它可以監聽你的資料是否發生變化,一旦發生變化,可以進行某些操作,那麼我們就來試試:

    <template>
       <div>
           <button @click="foo()">點選按鈕</button>
           <div>{{value}}</div>
       </div>
    </template>
    <script>
       export default {
           name: "",
           data() {
               return {
                   value:1,
               }
           },
           mounted() {},
           watch:{
               value:function(val,oldval){
                   console.log(val,oldval)
               }
           },
           methods: {
               foo() {
                   this.value=5
               }
           }
       }
    </script>
    
    <style scoped>
    </style>
    複製程式碼

    我們點選一下,看一下結果:當value被改變時,會在後臺列印出當前的值和改變前的值:


    vue-cli 實戰總結


    但當我們再次重複上一次的動作時,並不會再次列印結果,那是因為value值改變成5後,再次點選,還是同樣的值,value的值並沒有再次發生變化。


    watch 裡面有一個deep的引數,可以監聽object中屬性的變化。(我們上面使用的是number,而同樣使用上面的方法,並不能監聽到物件的屬性值的變化) 下面我們來使用deep來檢測一下物件屬性:

     <template>
        <div>
            <button @click="foo()">點選按鈕</button>
            <div>{{value}}</div>
        </div>
    </template>
    <script>
        export default {
            name: "",
            data() {
                return {
                    value:{
                        a:1,b:2
                    }
                }
            },
            mounted() {},
            watch:{
                value:{
                    handler(val,oldVal){
                        console.log("lalala",val,oldVal)
                    } ,
                    deep: true,
                    immediate: true
                }
            },
            methods: {
                foo() {
                    this.value.a=5;
                    this.value.b=6;
                }
            }
        }
    </script>
    
    <style scoped>
    </style>
    
    
    複製程式碼

    十、關於assetsstatic的區別,靜態資源到底該放哪裡?

    在我們搭建好的vue-cli的專案中會自動給我們建兩個資料夾來存放我們的資料,圖片之類的資產,這兩個分別是assetsstatic兩個,那麼我們怎麼來區分這兩個資料夾呢?在通過直譯我們瞭解到assets的中文意思為資產,而static的中文意思為靜態的,靜止的

    原因如下:

    assets目錄中的檔案會被webpack處理解析為模組依賴,只支援相對路徑形式。

    static/ 目錄下的檔案並不會被webpack處理:它們會直接被複制到最終的打包目錄(預設是dist/static)下。

    下面來一段程式碼,來現身說法:

    
    <template>
     <div class="hello">
       <div v-for="item in cityList" :key="item.id">
           <div >{{item.title}}</div>
           <div>城市圖片:<img :src="item.img"></div>
       </div>
     </div>
    </template>
    
    <script>
     export default {
       name: 'HelloWorld',
       data() {
         return {
           cityList: [{
               title: '北京',
               id: "001",
               img:"../assets/logo.png" //這行是不被識別的
             },
             {
               title: '上海',
               id: "002",
               img: "static/logo.png" //這個可以被正確顯示
             }
           ]
         }
       }
     }
    </script>
    
    
    
    複製程式碼

    頁面展示效果如下:

    vue-cli 實戰總結


    那麼我們看看在不寫在js中的圖片引入是否也會出現問題呢?

    <template>
      <div class="hello">
        <img src="../assets/logo.png" alt="logo"> 
        <img src="static/logo.png" alt="logo"> 
      </div>
    </template>
    
    <script>
      export default {
        name: 'HelloWorld',
        data() {
          return {
           
          }
        }
      }
    </script>
    
    
    
    複製程式碼

    來看一下頁面的反應:

    vue-cli 實戰總結


    效果證實,我們在html中的引入方式是不會受到影響的。 那如果我們必須要在js中使用assets中的圖片,該怎麼寫呢?

    <template>
      <div class="hello">
        <div v-for="item in cityList" :key="item.id">
          <div >{{item.title}}</div>
          <div>城市圖片:<img :src="item.img"></div>
        </div>
      </div>
    </template>
    
    <script>
      export default {
        name: 'HelloWorld',
        data() {
          return {
            cityList: [{
                title: '北京',
                id: "001",
                img:require("../assets/logo.png") //使用require()的方式引入即可
              },
              {
                title: '上海',
                id: "002",
                img: "static/logo.png"
              }
            ]
          }
        }
      }
    </script>
    
    
    複製程式碼

    好啦,接下來就是見證奇蹟的時刻了!!

    vue-cli 實戰總結


    綜上所述,總結為以下兩點:

    1.任何放在 static中檔案需要以絕對路徑的形式引用:/static/imgurl

    2.static放不會變動的檔案,assets放可能會變動的檔案。

    參考:https://juejin.im/post/59be4d325188257e764c8485 OBKoro1


    十一、關於打包後空白頁面的問題

    vue-cli在執行 npm run build 打包後,

    vue-cli 實戰總結
    會在dist 目錄下生成以下檔案
    vue-cli 實戰總結
    可是當我們執行命令打包後,開啟index.html的時候,顯示空白頁面,而且報錯,指明檔案找不到,如下:

    vue-cli 實戰總結

    接下來讓我們開啟cofig資料夾的index.js,找到build這個物件,將

    assetsPublicPath: '/'
    複製程式碼

    這個路徑地址改成

    assetsPublicPath: './',
    複製程式碼

    重新執行命令,重新打包,再開啟index.htnl,頁面即可顯示:

    vue-cli 實戰總結

    assetsPublicPath屬性作用是指定編譯釋出的根目錄,'/'指的是專案的根目錄 ,'./'指的是當前目錄。當我們打包後,index和static是放在dist目錄下,而static是和index是平級的,所以不應該在根目錄查詢檔案。

    參考:https://juejin.im/post/59ca4b96f265da0668760b60 OBKoro1

    十二、關於非同步懶載入路由的寫法

    在vue-cli自帶的腳手架的路由是如下這樣寫的:

    import Vue from 'vue'
    import Router from 'vue-router'
    import bus from '../bus'
    
    import HelloWorld from '@/components/HelloWorld'
    
    Vue.use(Router)
    
    export default new Route({
      routes: [
        {
        path: '/',
        name: 'HelloWorld',
        component: HelloWorld
       
        },
       
      ]
    });
    
    
    複製程式碼

    使用的是import 的方式引入進來的,那麼我們需要使用非同步的方式,該怎麼寫呢?

    import Vue from 'vue'
    import Router from 'vue-router'
    import bus from '../bus'
    
    Vue.use(Router)
    
    var router = new Router({
      routes: [
        {
          path: '/',
          name: 'HelloWorld',
          component: (resolve) => require(['@/components/HelloWorld'], resolve),
        },
        {
          path: '/login',
          name: 'login',
          component: (resolve) => require(['@/login'], resolve),
          
        }
      ]
    });
    bus.router = router
    
    export default router
    
    
    複製程式碼

    第二種方式:

    const Index = () => import( '@/views/index')
    const routers = [
        {
            path: '/',
            name: 'index',
            component: Index
        }
    ]
    
    
    複製程式碼

    十三、寫一個自定義指令

    在vue中除了可以寫元件,還可以使用自定義指令來實現某些特殊的操作,下面就拿一個類似官方的獲取input焦點的“基本款”的栗子?來演示。 我有個習慣,就是把相同的東西歸類,所以,我先去建了一個資料夾來存放我的指令,如下圖:

    vue-cli 實戰總結

    詳細程式碼如下: 在這裡定義並匯出我的自定義指令,指令裡包含我想實現的操作。(當前是一個獲取焦點的示例

    export const focus = (el) => {
        el.focus()
    }
    
    複製程式碼

    在使用的頁面,首先將指令檔案引入,然後配置到directive中,在需要使用到標籤內新增,注意指令前需新增:”v-“,如下所示: 我的指令name為focus,在標籤內寫成 “v-focuss”:

    <template>
      <div>
      <input type="text" v-focus>
      </div>
    </template>
    
    <script>
     import { focus } from "../../directives/index"
      export default {
        name: "",
        data() {
            return {}
        },
        directives: {focus}, //自定義指令
        components: {},
        mounted() {},
        methods: {}
      }
    </script>
    
    <style scoped>
    
    </style>
    
    複製程式碼

    vue-cli 實戰總結

    今日在掘金閒逛,看到vue的偏門操作,分享給大家: juejin.im/post/5adc99…

    vue的自定義指令直接操作dom較方便:

    先看directives/index頁面 :

    vue-cli 實戰總結

    接下來看一下呼叫頁面:

    vue-cli 實戰總結

    最後我們來看一下頁面:

    vue-cli 實戰總結

    再升級!新增引數的自定義指令

    vue-cli 實戰總結

    vue-cli 實戰總結

    vue-cli 實戰總結

    頁面的資料也可以寫成一個變數,使用變數來控制樣式:

    vue-cli 實戰總結

    vue-cli 實戰總結

    vue-cli 實戰總結

    下面是自定義指令的生命週期(我們可以在指令的生命週期中做我們想處理的事件): 1.bind:只呼叫一次,指令第一次繫結到元素時呼叫,用這個鉤子函式可以定義一個繫結時執行一次的初始化動作。 2.inserted:被繫結元素插入父節點時呼叫(父節點存在即可呼叫,不必存在於document中)。 3.update:被繫結於元素所在的模板更新時呼叫,而無論繫結值是否變化。通過比較更新前後的繫結值,可以忽略不必要的模板更新。 4.componentUpdated:被繫結元素所在模板完成一次更新週期時呼叫。 5.unbind:只呼叫一次,指令與元素解綁時呼叫

    好啦!大功告成,小夥伴們,動手試試吧!

    十四、關於打包後大圖片請求不到到問題

    今日在專案完成後,進行打包測試,本地開發好好的,但打包後發現登入頁面到背景圖片拿不到,但是其他logo小圖片是可以正常顯示,於是就很鬱悶,第一反應,想著應該是圖片太大了,未被壓縮,然後,就找到了如下位置:

    vue-cli 實戰總結

    想著把limit的範圍放大,可是那如果還有更大的圖片呢?這並不是個優雅的辦法。於是想到了萬能到度娘,就有了如下解決方法: my.oschina.net/u/1778998/b… css引入圖片再打包後,style-loader無法設定自己的publicPath,所以只要改變style-loader中的publicPath即可,在build/util.js檔案中ExtractTextPlugin的css路徑,手動新增publicPath引數。

    vue-cli 實戰總結

    新增後,再執行一次build,圖片就可以正常顯示。

    十五、跳過無需編譯及避免出現{{}}

    在我們的專案中應該會有很多情景,標籤內的內容是不需要編譯的,可是我們的程式碼並不知道,vue提供了一個可以直接跳過編譯的指令,供我們新增在純靜態標籤上。

    <div  v-pre> 直接跳過不需要編譯的標籤,加快編譯效率</div>
    複製程式碼

    還有一種情形,在頁面有用到{{}}賦值時,有時我們頁面阻塞或載入跟不上、頻繁重新整理時,可能會顯示未賦值的{{}},等拿到值後才能更新出來,這樣給使用者一種很不友好的體驗,同樣vue也幫我們想到了,vue提供了一個可以等待編譯結束,才會顯示標籤內容到指令.

    
    <div v-cloak> {{message}}直接結束編譯,避免出現閃爍花括號,配合css樣式書寫</div>
    
    //配合css 樣式完成
    <style scoped>
        [v-cloak]{display: none;}
    </style>
    複製程式碼

    十六、寫一個自定義過濾器

    vue有自己自帶的過濾器供我們使用,那我們如何來寫一個自定義過濾器呢?下面跟我一起操作吧!

    先去建立一個filter資料夾,來存放你的過濾器,並在檔案中寫出你想執行的過濾器的方法

    vue-cli 實戰總結
    在頁面的呼叫(類似自定義指令)
    vue-cli 實戰總結

    OBKoro1 的《你或許不知道的Vue的這些小技巧》很實用,推薦給大家!

    十七、vuex的簡單實現

    我們都知道vuex是用來實現vue各個元件資料傳輸功能的,不區分父子元件,全域性即可呼叫,讓我們的工程有了一個總的title,下來就讓試試: 先來建一個store,用來存放我們的初始化狀態,以及更改的方法:

    vue-cli 實戰總結
    接下來讓我們引入必備的依賴,以及相應的預設匯出:

    vue-cli 實戰總結
    程式碼如下:

    import Vue from 'vue';
    import Vuex from 'vuex';
    import { state as userState, actions as userActions, mutations as userMutations } from './stores.js';
    
    Vue.use(Vuex);
    
    const state = Object.assign({}, userState);
    const mutations = Object.assign({}, userMutations);
    const actions = Object.assign({}, userActions);
    
    
    export default new Vuex.Store({
        state,
        mutations,
        actions
    });
    
    複製程式碼

    最後讓我們來寫一下定義的初始值以及需要改變的方法:

    vue-cli 實戰總結
    程式碼如下:

    import {appRouter} from '../assets/data/menu';
    
    // 初始值
    export const state = {
        data: "0",
        menuList: appRouter,
        pageTitle:'初始值'
    
    }
    
    //如何改變 setData方法名
    export const mutations = {
        setData(state, val) {
            state.data = val
        },
        changePage(state,val){
            state.pageTitle = val
        }
    
    }
    //實現改變
    export const actions = {
        setData(contex, val) {
            contex.commit("setData", val)
        },
        changePage(contex,val){
            contex.commit("changePage", val)
        }
    }
    複製程式碼

    使用頁面,直接呼叫即可,不用其他依賴:

    // 獲取全域性變數
     console.log( this.$store.state.pageTitle)  // 初始值
     
     
     
    // 更改全域性變數
    this.$store.commit('changePage', '門店管理')
    複製程式碼

    十八、通過路由傳參,獲取引數,用於記錄狀態等

    如下圖情況:

    vue-cli 實戰總結

    我們需要在點選操作列的詳情進入下一個頁面,那麼我們是需要拿到此行的id 值,並且請求資料,然後再去渲染頁面,那麼我們如何通過路由來實現引數的傳遞呢? 借鑑

    第一種:通過path,query 來傳參

    // 傳參
    <div>
        <router-link tag="a" :to="{path:'detail',query:{id:1}}" >詳情</router-link>
    </div>
    複製程式碼
    // 接收引數
    <script>
    export default{
        mounted (){
           const id = this.$route.query.id;   //可以拿到從列表頁傳過來的id  
        }
    }
    
    </script>
    複製程式碼

    第二種:通過name,param 來傳參

    // 傳參
    <div>
        <router-link tag="a" :to="{name:'detail',params:{id:1}}" >詳情</router-link>
    </div>
    複製程式碼
    // 接收引數
    <script>
    export default{
        mounted (){
           const id = this.$route.params.id;   //可以拿到從列表頁傳過來的id  
        }
    }
    
    </script>
    複製程式碼

    上面兩個大同小異,接下來我們試試傳動態的引數:

    // 傳參
    <div>
        <router-link tag="a" :to="{name:'detail',params:{id:val}}" >詳情</router-link>
    </div>
    複製程式碼
    // 接收引數
    <script>
    export default{
        data () {
            val:1212
        },
        mounted () {
           const val = this.$route.params.val;   //可以拿到從列表頁傳過來的val值  
        }
    }
    
    </script>
    複製程式碼

    繼續升級,接下來我們試試,傳多個動態引數,每個key用逗號分割即可:

    // 傳參
    <div>
        <router-link tag="a" :to="{name:'detail',params:{id:id,name:name,age:age}}" >詳情</router-link>
    </div>
    複製程式碼
    // 接收引數
    <script>
    export default{
        data () {
            id:1212,
            name:"張小一",
            age:10
        },
        mounted () {
           const id = this.$route.params.id;   //可以拿到從列表頁傳過來的id值 
           const name = this.$route.params.name;   //可以拿到從列表頁傳過來的name值  
           const age = this.$route.params.age;   //可以拿到從列表頁傳過來的age值  
        }
    }
    
    </script>
    複製程式碼

    再升級,我們接下來傳一個陣列改如何操作

    // 傳參
    <div>
        <router-link tag="a" :to="{name:'detail',params:{list:[1,2,3,4]}}">詳情</router-link>
    </div>
    複製程式碼
    // 接收引數
    <script>
    export default{
        data () {
           arr:
        },
        mounted () {
           const list = this.$route.params.list;   //可以拿到從列表頁傳過來的list陣列  
        }
    }
    
    </script>
    複製程式碼

    !!!⚠️注意:一般情況下不建議使用路由傳過多的引數

    十九、關於跳轉路由後,清楚計時器的解決方法

    某天有看到一篇大佬的文章,講述的是跳轉頁面後,原頁面計時器仍然在執行的問題,正好自己也有寫國一個實時的鐘表的demo,於是就實驗了一番:

    頁面如下:

    vue-cli 實戰總結

    在每次進入頁面後呼叫了setTimeout,每秒去更新時間,為了驗證切換路由後,是否還會呼叫計時器,我在計時器後面加了一個列印數值來觀察,如下:

    ...
    ...
    ...
     this.inif.oSecond = seconds;
     this.inif.seconds = seconds * 6;
     this.inif.minute = minutes * 6 + seconds * (6 / 60);
     this.inif.hour = (hours - 12) * 30 + minutes * (360 / 12 / 60);
     
     //呼叫計時器
     this.timer = setTimeout(this.time, 1000)
     
     //列印參考值
     console.log(this.inif.seconds)
    複製程式碼

    可以看到後臺的列印情況:

    vue-cli 實戰總結

    現在我們切換路由去往其他的頁面,看看計時器是否停止:

    vue-cli 實戰總結

    實際證明,它並沒有停止,計時器依然在執行。這樣是非常消耗效能的。接下來我們來看看,大神是怎麼解決的:

    第一種解決方案:

    beforeDestroy 生命週期內進行清除:

    beforeDestroy() {
        clearInterval(this.timer);
        this.timer = null;
    }
    
    複製程式碼

    鑑於上面的方法,大神給出解釋:我們的程式碼獨立於清理程式碼,此種操作使得我們比較難於程式化的清理我們建立的所有東西。

    第二種解決方案:

    通過$once來監聽定時器,在beforeDestroy鉤子可以被清除

    ...
    ...
    ...
    
    this.timer = setTimeout(this.time, 1000)
    
    this.$once('hook:beforeDestroy', () => {
        clearInterval(this.timer);
    })
    
    複製程式碼

    兩種解決方案都可以將我們的問題解決,相對來說第二種較優雅!!! 借鑑於 chinaBerg 大神

    二十、關於打包後在dist資料夾的js裡面會有很多.map檔案

    專案打包後,程式碼都是經過壓縮加密的,如果執行時報錯,輸出的錯誤資訊無法準確得知是哪裡的程式碼報錯。而生成的.map字尾的檔案,就可以像沒有加密的程式碼一樣,可以準確定位到錯誤的位置,可以通過設定來不生成該類檔案,因為我們在生成環境是不需要.map檔案的,所以可以在打包時不用生成這些檔案。

    解決方案:

    在config/index.js檔案中,設定productionSourceMap: false,就可以不生成.map檔案

    二十一、監聽當前vueurl路徑,發生變化時重新整理頁面

    此需求是由於專案中一個列表中詳情點選後需要重新請求當前列的id,重新繪製當前頁面,如下:

    vue-cli 實戰總結
    首先我將我需要跳轉的資訊使用組合完整,如下:

     this.$router.push({
                        path: '/crowdmanage/crowddetails',
                        query: {
                            name: 'detail',
                            id: 17
                        }
                    });
    複製程式碼

    點選後url確實發生了變化,但vue並沒有檢測到,也就是url變化了,頁面並沒有重新去請求??????到底是什麼情況????---(此時第一感覺是:我的跳轉方式哪裡出現了問題嗎?為什麼vue 檢測不到呢?或者我要換成原生的跳轉??.....) 去諮詢了團隊的前端小哥哥,小哥哥給出了以下方式解決:---》》》》

    由於我的頁面元件裡面巢狀了小的元件,所以我需要在跳轉到的.vue的頁面新增:

     watch: {
                $route(to, from) {
                    this.initData();
                }
            }
    複製程式碼

    this.initData()是所有的請求資訊,當url發生變化後,watch就可以監聽到,然後重新去請求資料。啦啦啦啦啦 解決了。。。。。感謝小哥哥!!!

    二十二、編寫動態元件

    此時場景為:當一個元件裡面有3塊內容,而且這三塊內容每次展示都只展示一個tab,不會同時展現,如下圖:

    vue-cli 實戰總結
    此時,我們可以把這三個寫成動態元件,將其包裹在一個index檔案裡。

    首先,我們先建一個主index檔案,用於包裹三個子檔案,再建三個子的.vue檔案,這四個檔案並列即可。

    index.vue 主檔案內容如下(以下tabs來自UI元件iview):

    <template>
        <div>
            <Tabs size="small" @on-click="tabChange" v-model="tabContent">
                <TabPane v-for="(item,index) in tabList" :key="index" :label="item.label" :name="item.name"></TabPane>
            </Tabs>
            <--用:is的方式繫結動態變數,變數改變,隨之顯示的元件切換-->
            	<component :is="tabView"></component>
        </div>
    </template>
    
    <script>
      //引入三個子元件
        import A from "./A"
        import B from "./B"
        import C from "./C"
        export default {
            data() {
                return {
                    tabContent:"",
                    tabView: "",
                    tabList: [{
                            name: "a",
                            label: "標籤a"
                        },
                        {
                            name: "b",
                            label: "標籤b"
                        },
                        {
                            name: "c",
                            label: "標籤c"
                        }
                    ],
                }
            },
            // 註冊元件
            components: {
                A, // 標籤a
                B, // 標籤b
                C, // 標籤c
            },
            mounted() {
                this.tabChange(name)
            },
            methods: {
                //切換tab事件
                tabChange(name) {
                    this.tabView="A";
                    this.tabContent = name || "a";
                    if (name === "a") {
                        this.tabView = A;
                    } else if (name === "b") {
                        this.tabView = B
                    }else if (name === "c") {
                        this.tabView = C
                    }
                },
            },
            watch: {}
        }
    </script>
    
    <style scoped lang="less">
    
    </style>
    
    複製程式碼

    子元件的A.vue的檔案內容如下:

    <template>
        <!-- 第一個tab頁的內容  -->
        <div>
            我是標籤a的內容
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                  
                }
            },
            props: {},
            components: {},
            mounted() {},
            methods: {},
            watch: {}
        }
    </script>
    
    <style scoped lang="less">
    
    </style>
    
    複製程式碼

    其他幾個子檔案也如同A檔案一樣,這樣點選不同的tab 就會請求不同的.vue檔案。

    二十三、keep-alive 快取動態元件,以及它的引數,主要用於保留元件狀態或避免重新渲染。

    <keep-alive> 包裹動態元件時,會快取不活動的元件例項,而不是銷燬它們。

    Props

    • include - 字串或正規表示式。只有名稱匹配的元件會被快取。
    • exclude - 字串或正規表示式。任何名稱匹配的元件都不會被快取。
    • max - 數字。最多可以快取多少元件例項。
    <!-- 基本 -->
    <keep-alive>
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 多個條件判斷的子元件 -->
    <keep-alive>
      <comp-a v-if="a > 1"></comp-a>
      <comp-b v-else></comp-b>
    </keep-alive>
    
    <!-- 和 `<transition>` 一起使用 -->
    <transition>
      <keep-alive>
        <component :is="view"></component>
      </keep-alive>
    </transition>
    
    複製程式碼

    注意,``是用在其一個直屬的子元件被開關的情形。如果你在其中有 `v-for` 則不會工作。如果有上述的多個條件性的子元素,`` 要求同時只有一個子元素被渲染。

    • includeexclude屬性允許元件有條件地快取。二者都可以用逗號分隔字串、正規表示式或一個陣列來表示:
    <!-- 逗號分隔字串 -->
    <keep-alive include="a,b">
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 正規表示式 (使用 `v-bind`) -->
    <keep-alive :include="/a|b/">
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 陣列 (使用 `v-bind`) -->
    <keep-alive :include="['a', 'b']">
      <component :is="view"></component>
    </keep-alive>
    複製程式碼
    • max 最多可以快取多少元件例項。一旦這個數字達到了,在新例項被建立之前,已快取元件中最久沒有被訪問的例項會被銷燬掉。
    <keep-alive :max="10">
      <component :is="view"></component>
    </keep-alive>
    複製程式碼

    二十四、父子元件傳遞引數 props

    首先來寫一個父子元件傳參的例子?: 父元件內容:

    <template>
      <div>
        下面是引入的元件:
        <template-a :isItem="item"><template-a/>
      </div>
    </template>
    <script>
      import templateA from "./templateA"
      export default {
        data () {
          return {
            item:"000"
            
          }
        },
        components: {
          templateA
        },
        methods: {
          
        },
        mounted () {
          
        }
      }
    </script>
    <style>
    
    </style>
    
    複製程式碼

    子元件內容:

    <template>
      <div>
      我是templateA 元件,這是從父元件傳過來的引數: {{isItem}}
      </div>
    </template>
    <script>
    
      export default {
        data () {
          return {
            
          }
        },
        props:{
          isItem:{
            type:String,
            default:""
          }
        },
        components: {
        
        },
        methods: {
          
        },
        mounted () {
          
        }
      }
    </script>
    <style>
    
    </style>
    複製程式碼

    props 配置多個型別

    例如有時我們在傳遞引數的時候,不確定拿到是什麼型別,有可能是Number有可能是String,此時我們就可給props的預設型別時新增一個陣列,如下:

    props:{
        data: {     
    		type: [String, Number],
    		default: ''
    	},
    }
    
    複製程式碼

    這樣在拿到引數的時候,無論是string還是number都不會因為型別錯誤而報錯,加大了傳參的容錯率。 詳細參考

    • 補充:props 執行的比data早,所以在data中可以拿到props中的傳值。

    二十五、 非常好用的計算屬性 computed

    在我們的日常編碼中,往往會遇到很多需要判斷的條件、計算資料或者控制許可權等,如下:

    條件判斷: AA&&BB&&cc  ;
    計算資料: A+B-C-D 、   message.split('').reverse().join('');
    控制許可權: A === B || B===C ;
    複製程式碼

    以上的內容我們可以在標籤或者模版{{}}中進行判斷,計算,但如果邏輯較多,或者條件較複雜,這樣還在標籤或者模版上進行操作的話,我們的程式碼就看起來會很難理解,而且很冗餘,這時,我們可以把這些複雜的邏輯判斷放到 computed中進行計算,返給模版一個變數即可:

    <template>
      <div id="example">
        <p>未計算前的值: "{{ message }}"</p>
        <p>計算完畢返回的值: "{{ reversedMessage }}"</p>
      </div>
    </template>
    <script>
    
      export default {
        data () {
          return {
             message: 'Hello',     
          }
        },
        computed: {
        // 計算屬性的 getter 在這裡面進行一系列的計算,最後return出一個結果給模版
          reversedMessage: function () {
          // `this` 指向 vm 例項
            return this.message.split('').reverse().join('*')
          }
       },
        components: {
          
        },
        methods: {
          
        },
        mounted () {
          
        }
      }
    </script>
    <style>
    
    </style>
    複製程式碼

    頁面展示效果如下:

    vue-cli 實戰總結

    計算屬性是基於它們的依賴進行快取的。只在相關依賴發生改變時它們才會重新求值。這就意味著只要 message 還沒有發生改變,多次訪問reversedMessage計算屬性會立即返回之前的計算結果,而不必再次執行函式。

    參考:vue-computed

    二十六、元件之間的傳參 bus

    關於元件和元件之間的引數傳遞(非父子),vue推薦使用bus來進行傳遞,可進行上行、下行、平行、斜行各種傳遞,下面我們就來用bus來驗證。 首先需要先將它建立出來,可以放在公用的工具js中,最後統一引入到全域性mian.js中或者直接在mian中都可以,根據你情況建立並引入就行:

    import Vue from "vue";
    
    export default new Vue()
    複製程式碼

    此時就可以直接用了,下面讓我們來傳個引數試試:

    A頁面:

    <template>
      <div id="example">
        <Button @click="searIconClick" slot="append" icon="ios-search"></Button>
      </div>
    </template>
    <script>
    
      export default {
        data () {
          return {
             message: 'Hello',     
          }
        },
        methods: {
          // 當點選按鈕後,將message使用$emit傳給B頁面
          searIconClick(){
            this.bus.$emit("searInfo", this.message);  
          }
        },
      }
    </script>
    
    複製程式碼

    B頁面:

    <template>
      <div id="example">
           {{value}}
      </div>
    </template>
    <script>
    
      export default {
        data () {
          return {
             value: '',     
          }
        },
    
        components: {
          
        },
        methods: {
    
        },
        mounted () {
           this.bus.$on('searInfo', (message) => {
                    this.value = message;
                });
        }
      }
    </script>
    <style>
    
    </style>
    
    複製程式碼

    A 頁面傳送的事件名B頁面接受的事件名必須一致,而且需是全專案唯一的,不然會被其他傳參影響,或者影響其他傳參,我之前就出過這樣的錯,讓小姐姐找問題找來很久? !

    二十七、 計算屬性conputed,用來處理資料計算

    在我們專案中,有時需要進行一些計算,只要資料改變,計算實時更新,如資料不發生變化,快取計算結果。 效果展示地址:

    二十八、 vue中的錨連結跳轉

    vue中的錨連結和普通的html不同,關於vue中的錨連結可以參考vue 中的 scrollBehavior 滾動行為

    ----------------廢話不多說,直接上程式碼-----------

    router.js中的router 例項中


    const router = new VueRouter({
                routes,
                mode: 'history',
                scrollBehavior(to, from, savedPosition) {
                if (to.hash) {
                    return {
                        selector: to.hash
                    }
                }
            }
        })
      
    export default router;
    複製程式碼

    vue中點選跳轉的位置 使用<a>連結包起來

    <div>
        <a href="#populationInformation">A</a>
    </div>
    
    <div>
        <a href="#peopleCounting">B</a>
    </div> 
    <div>
        <a href="#trafficAnalysis">C</a>
    </div>
    複製程式碼

    在需要跳轉到的位置

    <div id='populationInformation '> A跳轉到此</div>
        
    <div id='peopleCounting'> B跳轉到此</div>
        
    <div id='trafficAnalysis '>C跳轉到此</div>
    複製程式碼

    要保證<a>標籤的 href 的地址要和下面id的值是相同的才可以完成相應的跳轉, 至於在router中的配置也是必須的

    二十九、 vue如何獲取當前頁面的url地址

    當場景需要我們獲取url地址,以做某些判斷操作時,我們可以使用下面的方法來獲取。

    1.獲取全部url

    console.log("完整的url地址:",window.location.href)  
    
    // 完整的url地址: https://juejin.im/editor/posts/5a1a6a6551882534af25a86b
    
    複製程式碼

    2.獲取路由路徑

    console.log("路由路徑:",this.$route.path)
    
    // 路由路徑:/activity/list
    
    複製程式碼

    3.獲取路徑引數

    console.log("路徑引數:",this.$route.query)
    
    // 路徑引數: {name: "detail", id: "109", tabView: "self", groupID: ""}
    
    複製程式碼

    (參考:十八、通過路由傳參,獲取引數,用於記錄狀態等)

    三十、兩種前端下載方式

    1.通過後端介面直接通過url跳轉到下載地址即可

    window.location.replace(http://172.******/exports/${id}/download`)
    複製程式碼

    2.通過後端介面前端實現下載請求

     this.$axios.get(`${this.$config.apiDomain}/crowds/exports/${row.id}/download-crowd`)
        .then(({data})=>{
        // data 直接傳入now Blob中
            const blob = new Blob([data], { type: 'cache-control,expires,pragma,content-type' })
            const downloadElement = document.createElement('a')
            const href = window.URL.createObjectURL(blob)
            downloadElement.href = href
            downloadElement.download = row.id+'.csv'
            document.body.appendChild(downloadElement)
            downloadElement.click()
    		document.body.removeChild(downloadElement) // 下載完成移除元素
    		window.URL.revokeObjectURL(href) // 釋放掉blob對
    	})
    
    複製程式碼

    借鑑地址

    值得推薦

    • vue的程式碼風格指南 裡面有vue 推薦的程式碼編寫風格,強烈推薦的,推薦及謹慎使用的各種風格示例,推薦大家看看,有助於開發效率提升。
    • vue的網頁執行工具 iVuewRun網頁版的vue,可直接執行使用,還可以分享給小夥伴!

    接下來我還會持續追加,看文章的小夥伴們可以新增一下關注哦!

    作者:Christine    
    出處:https://juejin.im/post/5a125827518825293b4fea8a
    版權所有,歡迎保留原文連結進行轉載:) 
    複製程式碼

    如果你對我對文章感興趣或者有些建議想說給我聽?,也可以新增一下微信哦!

    vue-cli 實戰總結
    如果親感覺我的文章還不錯的話,可以一下新增關注哦!

    最後:
            祝各位工作順利!
                            -小菜鳥Christine
    複製程式碼
  • 相關文章