Vue2 技術整理2:核心篇


2、組件化開發

2.1、認識組件概念

對於學Java的人來說的話,這個詞所要表達的意思再熟悉不過了,所謂組件就是:面向對象中的抽象、封裝思想,而所謂的組件化就是:把功能用多組件的方式搭配起來編寫( 有一個根組件,旗下有N多微型組件 ,粗暴理解就是:SpringCloud中的main()方法可以搭配很多不同功能的注解,main()方法就是根組件,不同功能的注解就是微型組件 ),那這些功能組成的應用程序就是一個組件化應用,因此:這樣做之后,好處就是利於維護和提高代碼的復用性了

但是對於前端的人來說,這個東西就需要特別解釋一下,直接下定義就是: 實現應用中局部功能代碼和資源的集合

瞄一下官網,它里面有一個圖

image

所以:現在就可以理解前面下的定義為什么是局部功能代碼和資源的集合了,局部功能就是某一個模塊,是針對這個模塊內部的,而這個模塊內部的編寫不就是CSS、HTML片段、JS代碼嗎,同時png、mp3等等這些就是資源咯

至於為什么要學組件化開發?

  • 一是因為做的應用頁面都是很復雜的,如果使用傳統的CSS+HTML+JS,那么就會出現很多的js文件,不利於維護和 編寫很費力的
  • 二是因為組件化開發可以極好的復用代碼、簡化項目代碼、所以也就提高了運行效率

同時組件又有單文件組件( 真實開發玩的 ) 和 非單文件組件

  • 單文件組件:就是指只有一個組件組成( 即:是一個.vue的文件 )
  • 非單文件組件:就是有N多個組件組成

2.2、非單文件組件

2.2.1、使用組件
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>玩一下組件</title>

    <script src="../../js/vue.js"></script>
  </head>

  <body>
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
      <!-- 3、使用組件 -->
      <person></person>
      <hr/>

      <hobbys></hobbys>

    </div>

    <script>
       // 去除瀏覽器控制台中的警告提示信息
      Vue.config.productionTip = false;

      // 玩組件三板斧
      // 1、創建組件
      const person = Vue.extend({
        // 這里在基礎篇中怎么玩就怎么玩,相應的也有watch、computed.....
        // 但是:切記:不可以用el和data必須是函數式
        /* 
          不可以用el的原因是:el指向的是具體的容器,這是根組件做的事情,現在這是是小弟
          不可以用data對象式,而必須用函數式:是因為對象是一個引用地址嘛( 玩java的人很熟悉這個對象的事情 )
                             如果用引用一是Vue直接不編譯、報錯,二是就算可以用對象式,那幾個變量都可以
                             指向同一個對象,那么就會產生:一個變量修改了對象中的東西,那么另一個變量指向
                             的是同一個對象,因此:數據也會發生改變
                             而函數式則不會,因為:函數式就會是哪個變量用的,里面的return返回值就是屬於哪個變量
        */

        // 使用模板,這個就需要直接寫在組件里面了,如果:放到div容器的模板中,是會報錯的
        template: `
          <div>
            <h2>{{name}}</h2>
            <h2>{{age}}</h2>
            <h2>{{sex}}</h2>  
          </div>
        `,
        // 切記:這里是使用data的另一種寫法 —— 函數式,必須用,前面基礎篇說過了
        data(){
          return {
            name: '紫邪情',
            age: 18,
            sex: '女'
          }
        }
      })

      // 再創建一個組件
      const hobbys = Vue.extend({
        template: `
          <div>
            <h2>{{one}}</h2>
            <h2>{{two}}</h2>
            <h2>{{three}}</h2>  
          </div>
        `,
        data(){
          return {
            one: '摳腳',
            two: '玩',
            three: '酒吧'
          }
        }
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el:'#app',
        // 這里面也可以使用這個編寫data,和以前一樣
        data:{},

        // 2、注冊組件
        components: {
          // 前為 正式在頁面中用的組件名( div模板中用的名字 )  后為組件所在位置
          // person: person,           // 這種同名的就可以簡寫

          // 簡寫
          person,
          hobbys
        }
       });
    </script>
  </body>
</html>

image

組件小結:

  1. Vue中使用組件的三板斧

    • 創建組件
    • 注冊組件
    • 使用組件( 寫組件標簽即可 )
  2. 如何定義一個組件?

    • 使用Vue.extend( { options } )創建,其中options 和 new Vue( { options } )時傳入的哪些option“幾乎一樣”,區別就是:
      • 1、el不要寫 ——— 因為最終所有的組件都要經過一個vm的管理( 根組件 ),由vm中的el決定服務哪個容器
      • 2、data必須寫成函數式 ———— 因為可以避免組件被復用時,數據存在引用關系
      • 另外:template選項可以配置組件結構
  3. 如何注冊組件?

    • 1、局部注冊: 靠new Vue的時候傳入components選項

    • 2、全局注冊:靠Vue。component( '組件名' , 組件 )

image

  • 真實開發中一般都是用前面玩的局部組件,局部變全局都是一樣的套路,去掉s,然后使用Vue來調,最后加入相應的名字和配置即可

  • 編寫組件標簽

<person></person>
2.2.2、使用組件的注意點

1、創建組件時的簡寫問題

  • 	  // 1、創建局部組件( 完整寫法 )
          const person = Vue.extend({
              template: `
                <div>
                    <h2>{{name}}</h2>    
                    <h2>{{age}}</h2>
                </div>
              `,
              data(){
                  return {
                      name: '紫邪情',
                      age: '女'
                  }
              }
          })
    
          // 簡寫形式
          const person2 = {
            template: `
                <div>
                    <h2>{{name}}</h2>    
                    <h2>{{age}}</h2>
                </div>
              `,
            data(){
                  return {
                      name: '紫邪情',
                      age: '女'
                  }
              }
          }
    

    上面兩種都可以。但是:簡寫形式在底層其實也調用了 Vue.extend()

    image

    image

    驗證完了,記得把源碼的斷點去掉

2、組件名的問題

(1)、組件名為一個單詞時,使用全小寫字母 / 首字母大小都沒問題

image

  • image

(2)、組件名為多個單詞組成時,全部用小寫 / 使用 - 進行分割都沒問題

image

image

還有一種就是上圖中的效果:駝峰命名

image

image

但是:這種駝峰命名需要注意,有些人就不可以( 因為:嚴格來說這種命名是后續的技術使用腳手架玩時的方式 ),但是:有些人就可以,比如我上圖中的效果,因為這是Vue版本的問題,要看源碼的話,從下圖這里往后看即可

image

(3)、注意組件名別和HTML中的原生標簽名一致,會沖突報錯,HTML的限制就是上圖中看源碼中的哪些,如果非要用HTML標簽名,讓人見名知意,那就在原生HTML標簽名前加一些特定的詞,如;my-input這種,千萬別用:input、h2....此類名字來命名組件名

3、關於組件在使用時的注意項

(1)、可以使用雙標簽,如:<my-info></my-info>,這種肯定沒任何問題

(2)、也可以使用自閉合標簽,如:<my-info/>,但是這種有坑,這種使用方式需要腳手架支持,否則s數據渲染會出問題

image

image

2.2.2.1、使用組件注意點總結

1、關於組件名

  • 一個單詞組成時

    • (1)、全小寫,如:person
    • (2)、首字母大寫,如:Person
  • 多個單詞組成時

    • (1)、全小寫,如:myinfo
    • (2)、使用 - 分割,如:my-info
    • (3)、駝峰命名,如:MyInfo,但注意:目前沒用腳手架之前最好別用,是因為指不定一會好使,一會不好使
  • 注意事項:

    • (1)、組件名最好別和HTML的標簽名一致,從而造成沖突( 非要用,可以采用加詞 / 使用 - 分割 )

    • (2)、可以在創建組件時,在里面配置name選項,從而指定組件在Vue開發者工具中呈現的名字

      image

      image

      • 此種形式在第三方組件時會見到
  • 2、關於組件標簽( 使用組件 )

    • (1)、使用雙閉合標簽也行,如:<my-info></my-info>
    • (2)、使用自閉合標簽也行,如:<my-info/> 。但是:此種方式目前有坑,會出現后續組件不能渲染的問題,所以需要等到后續使用腳手架時才可以
  • 3、創建組件的簡寫形式

    • const person = Vue.extend( { 配置選項 } ) 可以簡寫為 const person =
2.2.3、組件的嵌套
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>組件嵌套</title>

    <script src="../../js/vue.js"></script>
  </head>

  <body>
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
        <!-- 3、使用組件 -->
        <info></info>
    </div>

    <script>
       // 去除瀏覽器控制台中的警告提示信息
      Vue.config.productionTip = false;

      // 1、定義組件
      const person = {
          template: `
            <div>
                <h2>{{name}}</h2>    
                <h2>{{sex}}</h2>
            </div>
          `,
          data(){
              return {
                  name: '紫邪情',
                  sex: '女'
              }
          }
      }

      const info = Vue.extend({
          template: `
            <div>
                <h2>{{address}}</h2>    
                <h2>{{job}}</h2>
                <!-- 這個組件中使用被嵌套的組件 -->
                <person></person>
            </div>
          `,
          data(){
              return {
                  address: '浙江杭州',
                  job: 'java'
              }
          },

          // 基礎組件嵌套 —— 這個組件中嵌套person組件
          /* 
            注意前提:被嵌套的組件 需要比 當前嵌套組件先定義( 如:person組件是在info組件前面定義的 )
                     原因:因為Vue解析模板時,會按照代碼順序解析,如果定義順序反了
                           就會出現:這里用到的組件 在 解析時由於在后面還未解析從而出現找不到
          */
         components: {
             person,
         }
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el:'#app',
        data:{},

        // 2、注冊組件 —— 由於info組件中 嵌套了 person組件,所以在這里只需要注冊 info組件即可
        components: {
            info,
        }
       });
    </script>
  </body>
</html>

image

另一種嵌套:開發中玩的,我對那個div容器起的id值為app,是有用的

在開發中的嵌套是一個vm管理獨一無二的app( 就是application 應用的意思 ),然后由app管理眾多小弟

image

所以,現在來玩一下這種組件嵌套

  • <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>vm管app,app管眾多組件</title>
    
        <script src="../../js/vue.js"></script>
      </head>
    
      <body>
        <!-- 被 vm 實例所控制的區域 -->
        <div id="app"></div>
    
        <script>
           // 去除瀏覽器控制台中的警告提示信息
          Vue.config.productionTip = false;
    
    
          // 1、定義組件
          const person = {
              template: `
                <div>
                    <h2>{{name}}</h2>    
                    <h2>{{sex}}</h2>
                </div>
              `,
              data(){
                  return {
                      name: '紫邪情',
                      sex: '女'
                  }
              }
          }
    
          const info = Vue.extend({
              template: `
                <div>
                    <h2>{{address}}</h2>    
                    <h2>{{job}}</h2>
                    <!-- 這個組件中使用被嵌套的組件 -->
                    <person></person>
                </div>
              `,
              data(){
                  return {
                      address: '浙江杭州',
                      job: 'java'
                  }
              },
             components: {
                 person,
             }
          })
    
          // 再定義一個app組件,用來管理其他組件
          const app = {
            //   這個app組件沒有其他的東西,就是注冊和使用被管理組件而已
              components: {
                //   有其他組件也可以注冊在這里面,這里由於info管理了person,所以只注冊info即可
                  info
              },
              template: `
                <div>
                    <info></info>   
                </div>
              `,
          }
    
          // 創建 vm 實例對象
          const vm = new Vue({
            // 指定控制的區域
            el:'#app',
            data:{},
    
            // 由於組件被app管理,所以:只注冊app組件即可
            components: { app },
    
            // 使用組件
            template: `
                <div>
                    <app></app> 
                </div>
            `,
           });
        </script>
      </body>
    </html>
    

    image

2.2.4、認識VueComponent()函數

1、來看一下組件到底是誰?

基礎代碼

  • <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>認識VueComponent</title>
    
        <script src="../../js/vue.js"></script>
      </head>
    
      <body>
        <!-- 被 vm 實例所控制的區域 -->
        <div id="app"></div>
    
        <script>
           // 去除瀏覽器控制台中的警告提示信息
          Vue.config.productionTip = false;
    
          // 1、定義組件
          const person = Vue.extend({
              template: `
                <div>
                    <h2>{{name}}</h2>    
                    <h2>{{job}}</h2>
                    <h2>{{address}}</h2>
                </div>
              `,
              data(){
                  return {
                      name: '紫邪情',
                      job: 'java',
                      address: '浙江杭州'
                  }
              }
          })
    
          const app = {
              components: {person},
              template: `
                <div>
                    <person></person>    
                </div>
              `,
    
          }
    
          // 創建 vm 實例對象
          const vm = new Vue({
            // 指定控制的區域
            el:'#app',
            data:{},
            components: {app},
            template: `
                <div>
                    <app></app>    
                </div>
            `,
           });
        </script>
      </body>
    </html>
    
    image

現在就來見一下組件的真身( 在前面玩this的時候說過,this指向的是:Vue實例 / 組件實例對象 ),因此:用this就可以知道組件的真身

image image

既然知道了組件真身是VueComponent(),那么先去源碼中看一下它

image

源碼提取出來就是下面的樣子

  • var Sub = function VueComponent (options) {
           this._init(options);  <!--里面的重要邏輯封裝在了_init()中了,目前不要去看-->
         };
     
         return Sub
       };
    

    經過前面的分析和查看源碼得出兩個結論:

    1. 所有的組件指的都是VueComponent()
    2. 每一個組件都調用了VueComponent(),但是:它們都不一樣( 源碼中有嘛,每次都是創建了一個全新的sub,sub就是VueComponent(),最后把這個sub返回去了,驗證一下嘛
    image image

    但是:這里有一個有意思的東西,不了解原因的人很容易弄錯,也是第一條說的組件就是指VueComponent(),從而會出現不了解的人認為:每個組件都是調了同一個VueComponent(),來看一下

    image

    這兩個長得一模一樣,所以就會讓人誤會,玩java的人看到這個肯定熟悉得不得了,這就是一個構造函數嘛,所以理解起來也更容易,構造函數,那就是Vue每次解析模板時( div容器使用的組件標簽 ),就會去幫忙創建對應的組件,調用了構造函數,怎么調用的?new出來的嘛,所以:這兩個組件對象肯定不一樣( 前面先驗證是否一樣就是為了注意這點,看起來一樣,實質不一樣 ,兩個組件創建的是不同的VueComponent() )

    同時上面說到,Vue解析模板時,會幫忙去創建VueComponent(),那么是誰去幫忙創建的?

    • 答案就是創建組件時,里面的Vue.extend()去幫忙創建的,這不是我們程序員自己整出來的,看一下源碼

      image

VueComponent()小結

  • 組件本質是一個名為VueComponent()的構造函數,且不是程序員自己定義的,是Vue.extend()生成的

  • 我們只需要寫組件標簽( <person></person><person/> ) ,Vue解析時會幫我們創建組件的實例對象,即:Vue幫我們執行了new VueComponent( { options配置選項 } )

    • 注意點:每次調用Vue.extend(),返回的都是一個全新的VueComponent
  • 關於this的指向問題

    • (1)、在組件配置中:
      • data函數、methods函數、watch中的函數、computed中的函數,它們的this均是【VueComponent實例對象】
    • (2)、在new Vue()配置中:
      • data函數、methods函數、watch中的函數、computed中的函數,它們的this均是【vue實例對象,即:前面玩的vm 】
  • VueComponent實例對象,簡稱:vc( 或:組件實例對象 )

  • Vue實例對象,簡稱:vm

  • 但是:vm和vc也有一個坑

    image image

    觀察結構會發現:vm和vc如出一轍,什么數據代理、數據監測等等,vm有的,vc都有,所以vm中的配置項在vc中都可以配置,但是:vm和vc不能畫等號,它們兩個不一樣

    • vm是Vue實例對象,vc是組件實例對象

    • vm中可以使用el選項,而vc中不可以( 只要用el就報錯 )

    • 在vm中,data可以用函數式和對象式,但是在vc中data只能用函數式

    • vm是大哥,vc是小弟,vc是vm的組件( 或者說:算上app,那么vc就是vm的后代 ),或者直接說:組件實例對象vc是小型的Vue實例對象

    • vm和vc之間很多東西只是復用了而已( 這里說的復用,里面有大門道,vm和vc之間是有關系的,這里需要原型對象知識 —— 就一句話:函數肯定有ProtoType( 顯示原型屬性 ),而實例( 如:const person = vue.extend()中的person )肯定有 _ _proto _ _ ( 隱式原型屬性 ),而這二者指向的是同一個對象:即,該實例的原型對象,而vc和vm之間就是通過這二者關聯起來的

    • vm和vc之間的內置關系是:VueComponent.prototype._ _proto _ _ === Vue.prototype

      image

      圖中:VueComponent的原型對象通過 _ _proto _ _理論上應該直接指向object的原型對象,但是:Vue做了巧妙的事情:就是讓VueComponent的原型對象通過 _ _proto _ _指向了Vue的原型對象,這樣做的好處就是:讓組件實例對象 可以訪問到 Vue原型上的屬性、方法

以上的內容就屬於非單文件組件相關的,接下來就看單文件組件,也是開發中會做的事情

2.3、單文件組件

單文件組件:就是只有一個文件嘛,xxxx.vue

而xxxx就是前面說過的組件命名

  • 單個單詞:全小寫、首字母大寫
  • 多個單詞:用 - 進行分割、大駝峰命名
  • 而開發中最常用的就是:首字母大寫和大駝峰命名
2.3.1、疏通單文件組件的編寫流程

前提:如果自己的編輯器是vscode,那么就給編輯器安裝vetur插件,然后重啟vscode,這個插件就是為了能夠識別xxxx.vue文件的;如果自己是用的IDEA編輯器來寫的vue,那么安裝了vue.js插件就可以了

image
2.3.1.1、創建xxxx.vue文件

這個創建的就是單文件組件,前面玩非單文件組件,不是有三板斧嗎,對照來看

創建了xxx.vue之后,是一個空文件,里面要寫的東西就三樣(模板template、交互script、樣式style ),里面內容也對照非單文件組件來看

<template>
  <div class="temp">
      <!-- 這里面就是模板 以前在非單文件組件中用的template選項是怎么寫的,這里面就是怎么寫的-->
      <h2>{{name}}</h2>
  </div>
</template>


<script>
    // 這里面就是交互( data、methods、watch、computed..... )
    // 就是非單文件組件中的定義組件
/*    const person = vue.extend({
        // 這里就最好配置name選項了,一般都是當前創建的xxxx.vue中的xxxx名字即可
        name: 'Person',
        data() {
            return {
                name: '紫邪情'
            }
        },
        // 這里面還可以寫什么methods、watch.....之類的
    })
*/

    // 但是:上面是對照非單文件組件來寫的,在這個單文件中其實換了一下下
    // 1、這個組件是可以在其他地方復用的,所以:需要把這個組件暴露出去,然后再需要的地方引入即可
    /* 
        這里需要使用到js中模塊化的知識
        export暴露 import引入嘛
        但是:export暴露有三種方式
            1、分別暴露  export const person = vue.extend({ 配置選項 }),
                就是在前面加一個export而已
                可是:根據前面非單文件的知識來看,這個是可以進行簡寫的
                export person {}
            2、統一暴露 就是單獨弄一行代碼,然后使用 export { 要進行暴露的名字 },多個使用 , 逗號隔開即可
            3、默認暴露( vue中采用的一種,因為引入時簡單 )  export default 組件名{ 配置選項 }
                但是:組件名就是當前整個文件,所以可以省略
                默認暴露引入: import 起個名字 from 它在哪里
                而其他的暴露方式在引入時會有點麻煩
    */

   // 正宗玩法
   export default {
       name: 'Person',
       data() {
           return {
               name: '紫邪情'
           }
       },

       // 再配置其他需要的東西也行 如:methods、watch、computed.....
   }
</script>



<style>
/* 這里面就是template中的樣式編寫, 有就寫,沒有就不寫 */
    .temp{
        color: purple;
    }
</style>

xxx.vue文件,如果使用的是vscode+vetur,那么上面的模板有快捷鍵可以用 :就是輸入 <v 然后回車就可以生成了

image image
2.3.1.2、注冊組件到app中

前面玩過,vm管app,app管其他的小弟,所以需要一個app組件,創建一個app.vue

<template>
  <div>
      <!-- 使用app管理的組件 -->
      <person></person>
  </div>
</template>

<script>
    // 引入定義的person組件(要是有其他組件要引入那是一樣的套路)
    // 1Person.vue這個名字不正規啊,我只是為了排序才加了一個1
    import person from "./1Person.vue"  

    export default {
        name: 'App'
        // 注冊引起來的組件
        components: {person}  // 完成了引入和注冊之后,在這里面就可以用引入的組件了
    }
</script>

<style>
/* app是為了管理其他所有的組件,所以這個style其實不寫也行( 按需要來吧 ) */
</style>
2.3.1.3、將app和vm綁定起來

新建一個main.js文件,創建這個文件的目的:一是讓app和vm綁定,二是瀏覽器並不能識別.vue文件,所以根本展示不了,因此:需要將.vue文件轉成js文件,這樣瀏覽器就能解析了

// 1、引入app組件
import App from "./2App.vue"

// 2、把app組件和vm進行綁定
new Vue({
    // 這里面和以前一樣寫法,當然:這里的el值綁定的是容器id,怕誤會改成root也行
    el: '#App',
    components: {App}
})
2.3.1.4、創建容器

前面app組件和vm綁定了,但是vm中指定的el值,它綁定的容器還沒有啊,因此:創建index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>創建el容器</title>

    <!-- 
        記得要引入js,而此時就需要引入兩個js,一個是main.js,一個是vue.js 
        可是:在解析下面的容器時,可能會導致js渲染不及時出問題
        因此:引入js最好放在下面容器的后面引入
    -->
</head>
<body>

    <div id="App">
        <!-- 
            2、使用app組件,可以在這里使用,也可以不在這里使用
            直接在app.vue中使用template選項進行使用
        -->
        <App></App>
    </div>
    

    <!-- 
        1、引入js 
            vue.js是因為:main.js中new vue()需要它,所以:先引入vue.js
            其次再引入main.js
    -->
    <script src="../../../js/vue.js"></script>
    <script src="./3Main.js"></script>
</body>
</html>

經過上面的操作之后,玩Vue單文件組件的流程也就完了,整體結構就是如下所示

image

而整個流程按照解析的邏輯來看就是如下流程

  1. 進入index.html,創建了div id = "App"容器,然后引入vue.js,再引入main.js

s

image
  1. 但是:引入main.js,去main.js里面開始解析時,發現:需要引入App.vue,所以:接着引入App.vue
image
  1. 進入App.vue,又發現需要引入Person.vue
image
  1. 將所有東西都引入完了之后,就可以依次進行渲染了( 邏輯就不說明了 ),而經過上面的邏輯梳理之后會發現:main.js就是入口,是從main.js開始引入,從而把其他的東西也給引入進來了

當然:以上的東西弄完之后,還啟動不了,一啟動就會報錯。這是因為:瀏覽器不能解析ES6語法,這需要使用另外一個技術,腳手架來支持

image
2.3.2、認識腳手架 vue cli

cli全稱: command line interface 即:命令行接口工具,但是:一般說的都是腳手架,正規名字說起來太官方、繞口

在vue官網有這個腳手架生態

image
2.3.2.1、使用nodejs配置腳手架

前提:保證自己的電腦有nodejs

nodejs的配置很簡單,官網 進行下載、一直next、最后修改環境變量。LTS就是穩定版,而CURRENT就是更新版( 新特性就丟在這里面的,可能會出現bug,所以不推薦下載 )

有個注意點:選擇安裝目錄時,別把nodejs安裝到系統C盤了,不然很大可能出現權限不足,無法操作的問題,特別是:如果自己的電腦沒升級,還是家庭版的而不是專業版的,這種問題更常見

  • 出現這種問題就需要切換到管理員身份運行cmd才可以進行安裝vue-cli了,甚至有時會奇葩點:需要在管理員身份下運行npm clean cache –force
  • 然后再進入到C盤的用戶目錄下的appdata/roaming下把一個叫做nom-cache這個緩存文件刪了,最后再用管理員身份運行npm clean cache –force清除緩存,搞完這些才可以安裝vue cli腳手架

安裝成功之后是如下效果

image

查看一下是否成功?

  • 進入dos窗口( win+r,輸入cmd回車 ),以下內容表明成功
image

但是:現在npm的配置和緩存文件都在 C/user/appdata/roaming/npm 和 appdata/local/npm-cache 中的

image

因此:我們需要去改動這兩個地方( 知道了這兩個目錄,不用改也可以,后面什么事都可以不做了,對后續的操作沒影響的 ,嫌麻煩就可以改)

  1. 在安裝的nodejs中新建 node_globa l和 node_cache 兩個文件夾( 前為全局配置路徑,后為npm緩存路徑 )
image
  1. 執行如下命令( 路徑記得復制成自己的 ),另外記得用管理員權限打開命令行窗口
  • 全局設置
    C:\WINDOWS\system32>npm config set prefix "D:\install\Nodejs\node_global"
    
    C:\WINDOWS\system32>npm config set cache "D:\install\Nodejs\node_cache"
    
    
    檢查是否成功
    C:\WINDOWS\system32>npm config get prefix
    D:\install\Nodejs\node_global
    
    C:\WINDOWS\system32>npm config get cache
    D:\install\Nodejs\node_cache
    
    

    可見成功修改,但是:還需要做最后一步,去改環境變量( 使用msi安裝是默認配好了的 )

    在改環境變量之前,在剛剛新建的 node_global 目錄下,再新建一個 node_modules 目錄

    image
  1. 修改環境變量
image image

最后一路點OK即可,測試是否成功,可以選擇安裝一個vue包來測試

image

此時可能出現報一堆的ERROR,最后一行的大概意思就是讓使用 root/ admin...用戶( 也就是讓用管理員運行dos窗口,再執行命令 )

報一堆ERROR錯誤的解決辦法:

此時:做一個操作即可,回到nodejs安裝的根目錄

image

右鍵選擇屬性、安全、高級

image

當然:要是自己的電腦在這個安全界面中,直接編輯權限,然后把“寫入權限”√上是可以的,那就直接√上,要是不行就接着往后看

image image

然后再使用npm install -g xxx就可以了

安裝之后,在剛剛新建的 node_global 和 node_cache 中是有東西的

image

如果想要把全局配置恢復為初始化配置的話,也很簡單,系統C盤用戶目錄/.npmrc的文件,刪了就可以了

image

配置成功了nodejs之后,就可以使用npm指令了

但是:npm是國外的,我們拉取東西時就猶如隔了一道牆,很慢

因此:拉取淘寶的鏡像,從而使用cnpm來代替npm指令,拉取淘寶鏡像鏈接:npm install -g cnpm --registry=https://registry.npm.taobao.orgnpm config set registry http://registry.npm.taobao.org

這兩個淘寶鏡像,建議用前者,拉取鏡像這里開始就一定要保證自己的網絡流暢,不然很容易導致一是淘寶鏡像拉取失敗( 看起來成功了,但是一用就報cnpm不是內部命名 ,這種情況要么權限不夠,需要管理員身份打開dos窗口;要么cnpm沒拉完整),二是后面安裝腳手架時,要是網絡不好,也很容易出現看起來成功了,但是:一用就發現vue不是內部指令

下圖是我重新拉取一遍的效果

image
  1. 全局安裝@vue/cli。指令: ``
  • npm 是nodejs的指令 拉取了淘寶鏡像之后,就可以使用cnpm代替了
  • install 就是安裝的意思
  • -g 是全局安裝
  • @vue/cli 是安裝的東西

有個注意點:要是有人知道可以使用 npm install -g vue-cli 這樣安裝腳手架的話,可以用,沒錯的,但是:目前別這么安裝。它安裝的腳手架是2.x的,用這種方式安裝的不能保證vue( 目前版本是1-3 )和vue-cli( 目前版本是1-4 )的版本很適合,所以后續使用一些命令時可能會出現版本不足的問題,讓把版本升級,而使用@vue/cli安裝的是最新版本

  1. 創建一個文件夾,並進入目錄中。 使用指令:vue create xxxx
  • vue create 是cli3.x的命令,要是前面安裝腳手架時是亂整的,就會發現:這個命令用不了,要是出現這樣的話,那么執行一遍這個命令,會提示你:卸載以前的cli,然后執行什么命令安裝cli

  • xxx 就是要創建的項目名

    image

    image image

    出現如上圖就說明在開始拉取依賴了

  1. 啟動項目
image image image

想要退出啟動的程序,一是直接點窗口右上角的×,二是按兩次ctrl+c即可

以下內容是以前使用 vue init webpack xxx 來安裝的vue-cli

image

查看一下自己的vue-cli安裝成功沒有,指令: vue list

image

vue-cli安裝成功之后,想找它就在 C/user/appdata/roaming/npm/node_modules中可以看到

image

當然:有可能有些不聽勸的人在安裝nodejs時,搞了一些不必要的操作,導致有些文件需要管理員權限才可以

因此:就會出現這里安裝vue-cli時失敗,報的錯就是什么node_glob.....爪子之類的,總之:就是權限不夠,然后使用管理員身份做前面的操作就發現突然吃雞了,這就是典型的權限不夠導致的。這樣的話,以后:你使用vue相關的東西時,就都得使用管理員權限才可以進行操作

  1. 創建一個文件夾,然后進入文件夾,使用指令:vue init webpack xxxx,進去之后會做一些操作
  • init 就是初始化嘛
  • webpack 就是骨架,就像建樓一樣建好的地基
  • xxxx 就是要創建的項目名

image

image image image

當然:上圖中的那個babale單詞可能是錯的,我記不清了^ _ ^ 。反正單詞大概是那個

image image image

上面這些記不住沒關系,在沒選擇安路由之前一路回車,然后開始選擇時一路no,最后選擇use npm即可。后續把東西學完了,那就可以把對應的東西裝上了

拉取完了之后,就是下面的樣子

image

然后進到創建的項目中,使用 npm run dev ,會得到一個網址,瀏覽器訪問就可以了

image

上面這個窗口別關了啊,不然使用地址訪問不了的

image
2.3.2.2、分析cli構建的項目

使用vscode打開剛剛編譯的項目

image
  1. package-lock.json
image
  1. package.json
image

以上就是基礎的東西,接下來就對照前面手寫的單文件組件思路來分析接下來的東西,那時說過:main.js是入口,所以cli腳手架程序就從main.js入手( 在cli中為什么它是入口?腳手架底層做的處理 )

  1. main.js
image
  1. 引入了App.vue組件,那就接着分析App.vue組件
image

注意:

  • assets目錄是專門用來放靜態資源的,如:png、mp3...( 后端的人就把這個目錄當做是SpringBoot中的那個static目錄 )
  • components目錄是專門用來放組件的( App.vue是一人之下【vm】萬人之上【其他任何組件】,所以不在這里面 )
  1. 上面引入了helloword組件,而那里面就是一堆正常的組件寫法

  2. 分析的差不多了,但是:還少了一個重要的東西,容器在哪里?

就在index.html中,而這個東西有一個專門的public目錄來放

image

經過前面的分析之后,再結合上次寫的單文件組件,就知道對應的東西寫在哪里了

順便說一下:vscode中啟動vue程序,按ctrl + 飄字符( esc下面、tab上面的那個按鍵 )喚出控制台,后面的就知道怎么做了( 做了修改之后,按ctril+s保存時會自動重新編譯 )

image
2.3.2.3、認識render()函數

把前面編譯好的例子改一下( 我的是把前面疏通流程的代碼拷貝進來的 )

image image

原因就是:代碼中的一句代碼

image

那就去看一下vue到底有哪些版本?按住ctrl+鼠標點引入的vue哪里,點vue就進去了

image

點開它的包說明:就發現引入的是 dist/vue.runtime.esm.js

image

隨便選擇一個右鍵在資源管理器中顯示,就可以看到文件大小( 可以和vue.js對比,就少了100kb作用而已,少的就是模板解析器,但是:少的這部分用處很大 )

image

vue為什么要搞出這么多版本?

  • 這是因為vue其實就是將webpack進行了封裝,然后添加了一些技術,從而搞出來的,所以webpack在進行打包時會將.vue轉成.js從而實現渲染( 后端人員不懂webpack的,就粗暴的把它當做是maven中的install打包,當然:compile編譯等等這些指令功能也在vue中有相同的效果的實現機制 )
  • 而程序編寫完了之后,webpack本身就支持將.vue轉成.js,那使用webpack打包時,模板解析器就不應該出現了( 模板解析器就是編寫時解析而已 ),所以真實打包時如果出現了模板解析器出現一個騷氣的事情,舉個例子:去做某事

image

  • 整出那么多版本的原因就知道了唄,減少程序體積、提高性能嘛

回到前面報的錯,怎么解決?控制台已經把答案給的很明確了

  1. 使用包含模板解析器的vue就可以了

  2. 使用render()函數實現模板解析器的效果

  3. 使用包含模板解析器的vue最簡單。引入的vue有問題,那就改一下嘛

image image
  1. 使用render()函數來實現解析template的功能
image image

知道了render()的結構,那就去實現解析template的功能

image

然后蘭姆達表達式簡寫不就成原來的樣子了嗎

image
  • App就是h2,因為:App是一個組件,使用時就是
  • 這個render()函數也就在vm綁定容器時會用到,其他地方見都見不到的
2.3.2.4、關閉語法檢測

官網中有,改cli的全局配置也是一樣的套路

image

官網里面就是說新建一個 vue.config.j s的文件,這個文件必須和package.json是同級目錄,然后要配置東西時,找對應的配置項,然后復制粘貼對應的內容( 或改動一點自己要的配置項即可 )

關閉語法監測,就是名為lintOnSave的配置項罷了

創建vue.config.js文件

image image

經過上面的操作之后,就算定義一個變量,然后后面一直沒用這個變量也不會導致項目啟動不了了,否則:使用npm run serve時,就會報錯,導致啟動不了

而創建這個vue.config.js文件能夠修改cli的配置是因為:cli是在webpack的基礎上做出來的,而webpack是在nodejs的基礎上整出來的,因此:程序最后是將自己寫的vue.config.js去和webpack中的進行了合並,從而就成功了

注意點:cli中不是什么都可以修改的

image

想要重新改動,就在剛剛新建的vue.config.js中配置即可,但是注意:

  • vue.config.js每一次更新都要使用npm run serve重新啟動項目,否則不生效
  • vue.config.js中不可以說:不用了加個注釋,然后等后面用的時候再解開注釋,這種是不行的,要么就配置,要么就不配置,否則:啟動不了項目

最后:vue隱藏了webpack的配置,要想查看默認配置的話,那就使用 ctrl+飄字符 喚出控制台后,輸入:vue inspect > output.js,然后就會在項目中生成一個output.js文件,里面就有默認配置

2.3.3、認識ref屬性

這個屬性是用來給“元素”或“子組件“注冊引用信息( 也就是id屬性的替代者 ),這個小東西很重要,關系到后續組件與組件之間的通信

重新復制一份src文件夾,用的時候把名字改回來就可以了( 需要哪一個就把哪一個改為src,然后執行npm run serve就行了 )

image

運行效果如下:

image

現在有一個需求:獲取下圖中的DOM結構

image

使用傳統js來操作的話,就是document.getElementById進行獲取,但是:Vue中提供得很ref屬性來進行操作:ref屬性用來給“元素”或“子組件“注冊引用信息( 也就是id屬性的替代者 ),所以來見識第一個“元素”注冊引用信息( 在HTML元素中這個ref屬性就和id屬性是一樣的效果 )

image

第二種:ref屬性是在子組件上的。這種很重要,后面組件與組件之間交互的基礎

image image image

但是:這種和id就不同了,id是直接獲得了子組件的DOM結構,而ref是獲得了組件本身VueComponent

image image

ref屬性小結

  • 被用來給元素( id的替代者 )或子組件注冊引用信息
  • 應用在HTML標簽上獲取的是真實DOM元素,應用在組件標簽上獲取的是組件實例對象( vc )
  • 使用方式:
    • 做標識: <h1 ref="xxx">......<h1><Person ref="xxx"><Person>
    • 獲取:this.$refs.xxx
2.3.4、props配置-獲取外傳數據

組件中的props配置就是為了獲取從外部傳到組件中的數據

這個東西很有用,后續玩子傳父、父傳子就需要這個東西,而且開發中這個東西會經常看到

image
2.3.4.1、只接收數據
  1. Person.vue組件編寫內容
<template>
  <div>
      <h2>{{name}}</h2>
      <h2>{{sex}}</h2>
      <h2>{{age}}</h2>
      <h2>{{job}}</h2>
      <h2>{{address}}</h2>
  </div>
</template>

<script>
    export default {
        name: 'person',
        
        // 使用props配置,使這個Person組件中的數據從外部傳進來( 封裝的思想來咯 )
        // 第一種方式:只接收數據即可(數組寫法) - 此種方式:接收的數據統統都是字符串
        props: ['name','sex','age','job','address']
    }
</script>
  1. App.vue組件編寫內容
<template>
  <div>
      <h1 ref="content">歡迎來到對抗路,對手信息如下</h1>
      <!-- 使用組件 並 傳入數據 -->
      <Person name="紫邪情" sex="女" age="18" job="java" address="浙江杭州"/>
  </div>
</template>

<script>
    import Person from "./components/Person.vue"

    export default {
        name: 'App',
        components: {Person},
    }
</script>
  1. ctrl+s重新編譯
image

效果如下

image
2.3.4.2、接收數據 + 數據類型限定
image image

至於限定類型有哪些? 可以是下列原生構造函數中的一種

  • StringNumberBooleanArrayObjectDateFunctionSymbol、任何自定義構造函數、或上述內容組成的數組
2.3.4.3、接收數據 + 限定類型 + 數據有無接收的必要 + 數據默認值

這個東西,玩java的人看起來很熟悉,和ElasticSearch中的mapping映射很像

image image
2.3.4.4、處理外部傳入數據類型問題
image image

問題就輕輕松松解決了

2.3.4.5、解決props接收數據之后,修改它的值

props配置中不是什么屬性名的值都可以接收的,如:key、ref

image image image

意思就是:key不能作為props接收的數據,原因就是因為:key這個屬性被Vue給征用了,Vue底層需要使用diff算法嘛,它用了這個key關鍵字,所以我們不可以用它

回到正題,props接收了數據怎么修改它?

  • 首先要知道,props被底層監視了的,所以它的東西只可以接收,不可以修改,想要接收了數據,再修改它,我們就需要借助data,中轉一下

  • 先來看不中轉,然后修改props中數據的下場

    image
  • 使用data中轉,從而修改數據

    image
2.3.4.6、props配置總結
  • 功能:讓組件接收外部傳進來的數據

  • (1)、傳遞數據

    • <Person name="xxxx">
  • (2)、接收數據

    • 1)、只接收

      • props: ['name']
    • 2)、接收數據 + 數據類型限定

      • 	props: {
          		name:String
          	}
        
    • 3)、接收數據 + 數據類型限定 + 必要性限制 + 數據默認值

      • 	props: {
          		type:String,
          		required:true,
          		default:'紫邪情'		注:一個數據字段不會同時出現required和defautle
          	}
        
  • 注意:props中的數據是只讀的,Vue底層會監測對props的修改,如果進行了修改,就會發出警告

    • 如果業務需要修改,則:把props中的數據復制一份到data中,然后去修改data中的數據就可以了
    • 須知:vue中優先使用props中的數據,然后再使用data中的數據( 可以使用data中的名字和props中的名字一樣,然后去渲染,發現渲染出來的數據是props中的 )
2.3.5、mixin混入 / 混合

這個東西就是把多個組件中共同的配置給抽取出來,然后單獨弄成一個js文件,使用一個對象把相同配置給封裝起來,然后在需要的組件中引入、使用mixins配置進行使用即可

這種思想后端的人再熟悉不過了,工具類的編寫不就是這么回事嗎

2.3.5.1、使用

基礎代碼

image image

在上面的代碼中,methods中的代碼是相同的,因此:使用mixin混入來進行簡化,也是三板斧而已

  1. 新建js文件( 名字根據需要取即可 )
image
  1. 在需要的組件中引入抽取的代碼和利用mixins配置進行使用
image
  1. 運行效果
image

但是:mixin混入有一些注意點

  1. 除了生命周期,如果其他配置是在mixin中定義了,同時在組件中也定義了,那么:優先使用的是組件中自己定義的( 無論二者相同與否都一樣 )
image image
  1. 如果在mixin中定義了生命周期鈎子函數,那么:優先使用mixin中的鈎子函數
image

如果二者不同,那么就會造成二者中定義的都會被調用

image image

另外:mixin混入是支持全局配置的,不過這種操作不當會出現問題,因此:目前不建議用,需要時再玩吧,思路如下:

  1. 一樣的創建js文件
  2. 在App.vue中引入
  3. 在App.vue中使用vue.mixin( 暴露對象1 ) 、vue.mixin( 暴露對象2 ).......
  • 使用了這三板斧之后,就可以實現全局配置了
2.3.5.2、mixin混入總結

功能:把多個組件共同的配置提取成一個混入對象

使用方法:

  1. 定義混入,如:
  • 	暴露方式 const 對象名 {
      		data(){......},
             methods:{........},
             ........
        }
    
  1. 在需要的組件中引入混入

  2. 使用混入,如:

  • 1)、局部混入:mixins: [ xxxxxx , ......... ] , 注意:這里必須用數組
  • 2)、全局混入:Vue.mixin( xxxxx )
2.3.6、插件

這個東西的作用很大,它可以合理的增強Vue

使用,也簡單,還是三板斧

  1. 創建js文件( 包含install()方法的一個對象 )

  2. 引入插件

  3. 使用插件

2.3.6.1、玩一下插件

基礎代碼效果

image
  1. 創建一個包含 install() 方法的對象的js文件
image
  1. 在main.js中引入、使用插件
image
  1. 效果如下
image

可以得知:創建的插件中傳遞的那個參數Vue就是vm( Vue實例對象 )的締造者 —— vue構造函數

得到上面哪那個結果就很重要了,試想:我們使用這個構造函數做過什么事?

  • 自定義全局指令 Vue.directive

  • 定義全局過濾器 Vue.filter

  • 定義全局混入 Vue.mixin

  • ........

  • 把這些東西放到創建插件的install()中可行?它接受的參數就是Vue嘛

正宗玩法

  1. 創建包含install()方法的對象的js文件
image
  1. 在main.js中引入插件、應用組件
image
  1. 使用插件中的東西
image
  1. 效果如下:
image

當然:我們也可以給插件中傳東西進去

image image image
2.3.6.2、插件總結

功能:用於增強Vue

本質:是包含install()方法的一個對象的js文件,install的第一個參數是Vue,第二個以后的參數是插件使用者傳遞的數據

插件的玩法:

  1. 定義插件:
  • // 1、創建插件  export default 是自己選擇的暴露方式
    export default {
        install(Vue,[ other params ]){
            
            // 定義全局過濾器
            Vue.filter( ..... ),
                
            Vue.directive( ...... ),
                       
            Vue.mixin( ....... )
            .........
        }
    }
    
    
  1. 在main.js中引入插件

  2. 在main.js中向Vue應用插件 Vue.use( 插件名 )

  3. [ 使用插件中定義的東西 ] ———— 可有可無,看自己的代碼情況

  • 這里注意一個東西:定義插件中的install()第一個參數是Vue,即:vm的締造者,Vue構造函數( 這里可以聯想原型對象,也就是前面說的vm和vc的內置關系:VueComponent.prototype._ _proto _ _ === Vue.prototype,這也就是說在Vue身上加點東西,那么:vm和vc都可以拿到,如:

    • 	Vue.prototype.$myMethod = function(){ ...... }
        	Vue.prototype.$myProperty = xxxx
        
      prototype 路線是加東西
      _ _proto_ _ 路線是取東西
      
2.3.7、scoped局部樣式

作用:讓樣式在局部生效,防止沖突

寫法:<style scoped>

假如有兩個組件,里面都用了同一個class類名,但是做的style卻是不一樣的

image image

此時如果把兩個class名字改成一樣呢?開發中樣式多了這種事情是在所難免的

image

憑什么就是Person2.vue組件中的樣式優先?這和App.vue中引入組件的順序有關

image

不然:把組件引入的順序換一下就發現變了

image

那上述樣式沖突了怎么解決?答案就是使用scoped限制作用域( 后端人員,這個東西熟悉得很,maven中依賴的作用域,是一樣的效果 )

image image

這個小技巧在開發中會經常見到

當然:style標簽不止支持scoped屬性,還可以用其他的

image

另外:less需要less-loader支持,所以需要安裝less-loader,但是:有坑( 版本的問題 )

image

cli中的webpack版本

image

安裝適合cli的webpack的less-loader版本

image

最后還有一個問題:scoped使用在App.vue中就會發生很詭異的事情

  • App.vue是大哥,所以這里面的style會全局生效( 也就是多組件都在使用的樣式,就可以提到App.vue中寫,然后在其他需要的組件中使用即可 )
  • 但是:如果App.vue中style使用了scoped,那么就會導致:樣式只在App.vue中有效,那么:其他組件中想要用,那對不起,管不了,最后頁面就會出現詭異的事情 —— 不是自己寫的樣式的樣子
  • 所以:App.vue中最好別用scoped屬性,而其他組件中最好都加上scoped屬性
2.3.8、組件化應用應該怎么去寫?

實例:實現如下的效果( 就是一個人名錄入,然后可以對名字做一點操作罷了 )

image

組件編寫流程( 基本上都是一樣的套路 ),接下來按照套路去弄就可以了

2.3.8.1、分析結構 / 拆分組件

根據頁面結構來看,可以拆分成如下的結構:

  1. 外面大的框就是一個組件 —— 也就是App.vue父組件,而App組件中又包含的如下組件:
  • 1.1、輸入框是一個組件( 子 )
  • 1.2、人名的展示框是一個組件( 子 ,卻是下面兩個的“父” )
    • 1.2.1、然后發現展示框里面又有每一個人名組件( 子 )
    • 1.2.2、還有一個全選 / 顯示已選人數的組件( 子 )
2.3.8.2、創建對應組件並編寫內容

1、創建並編寫組件對應內容( 統稱編寫靜態組件 )

  • 1)、App組件

    • (1)、HTML結構

      • <template>
          <div id="root">
              <div class="name-container">
                <div class="name-wrap">
        
                  <NameHeader></NameHeader>
                  <NameList></NameList>
                  <NameFooter></NameFooter>
        
                </div>
              </div>
          </div>
        </template>
        
        <script>
        import NameHeader from "./components/NameHeader.vue"
        import NameList from "./components/NameList.vue"
        import NameFooter from "./components/NameFooter.vue"
        
            export default {
                name: 'App',
                components: {NameHeader,NameList,NameFooter}
            }
        </script>
        
    • (2)、CSS樣式 + 后續需要的通用樣式

      • body{  
          background: #fff;
        } 
        
        .btn {
          display: inline-block;
          padding: 4px 12px;
          margin-bottom: 0;
          font-size: 14px;
          line-height: 20px;
          text-align: center;
          vertical-align: middle;
          cursor: pointer;
          box-shadow: inset 0 1px rgba(255,255,255,0.2),0 1px 2px rgba(0, 0, 0, 0.05);
          border-radius: 4px;
        }
        
        .btn-danger {
          color: #fff;
          background-color: #da4f49;
          border: 1px solid #bd362f;
        }
        
        .btn-danger:hover {
          color: #fff;
          background-color: #bd362f;
        }
        
        .btn:focus {
          outline: none;
        }
        
        .name-container {
          width: 600px;
          margin: 0 auto;
        }
        
        .name-container .todo-wrap {
          padding: 10px;
          border: 1px solid #ddd;
          border-radius: 5px;
        }
        
        
  • 2)、輸入框組件

    • (1)、HTML結構

      • <div class="name-footer">
            <label>
                <input type="checkbox">
            </label>
            <span>
                <span>已選擇0</span> / 共計2
            </span>
            <button class="btn btn-danger">清除已選人員</button>
        </div>
        
  • 3)、人名展示框

    • (1)、HTML結構

      • <template>
            <NameObj></NameObj>
        </template>
        
        <script>
        import NameObj from "./NameObj.vue"
        
            export default {
                name: 'NameList',
                components: {NameObj}
            }
        </script>
        
    • (2)、CSS樣式

      • /* #region list */
          .name-main {
              margin-left: 0px;
              border: 1px solid s#ddd;
              border-radius: 2px;
              padding: 0px;
          }
        
          .name-empty {
              height: 40px;
              line-height: 40px;
              border: 1px solid #ddd;
              border-radius: 2px;
              padding-left: 5px;
              margin-top: 10px;
          }
        
        /* #endregion */
        
  • 4、每個人名展示

    • (1)、HTML結構

      • <template>
            <ul class="name-main">
                <li>
                    <label>
                        <input type="checkbox"/>
                        <span>xxxxx</span>
                    </label>
                    <button class="btn btn-danger" style="display:none">刪除</button>
                </li>
            </ul>
        </template>
        
        <script>
            export default {
                name: 'NameObj',
            }
        </script>
        
    • (2)、CSS樣式

      • /* #region item */
          li {
            list-style: none;
            height: 36px;
            line-height: 36px;
            padding: 0 5px;
            border-bottom: 1px solid #ddd;
          }
        
          li label {
            float: left;
            cursor: pointer;
          }
        
          li label li input {
            vertical-align: middle;
            margin-right: 6px;
            position: relative;
            top: 1px;
          }
        
          li button {
            float: right;
            display: none;
            margin-top: 3px;
          }
        
          li:before {
            content: initial;
          }
        
          li:last-child {
            border-bottom: none;
          }
        
        /* #endregion */
        

運行效果如下:

image

自此:靜態組件編程就搞定,后續就可以做數據的動態綁定和交互這些了

將純HTML + CSS + JS轉成組件化開發也是一樣的套路,流程如下:

  1. 把整個HTML結構放到App.vue組件的template模板中

  2. 把所有的CSS放到App.vue組件的style中

  3. 有JS的話,那么把js文件創好,然后引入到App.vue組件中

  4. 開始去分析結構,然后拆分成組件,之后把對應的內容放到對應組件中,最后做后續的動態數據綁定、交互即可

2.3.8.3、動態數據綁定

按照分析,要展示的數據是一堆數據,而數據顯示的地方是NameList,所以:data數據就放到NameList中去。本實例中數據放到這里有坑啊,但是:先這么放,后續遇到坑了再調整,所以改一下源碼

image

數據是弄好了,但是:真正展示數據的是NameObj組件來顯示出來的,而NameObj是NamelList的子組件( 這就是:父傳子 ),這種就需要借助props配置項( 從外向內傳嘛 ),所以:開始操作

  1. 父傳子
image image image
  1. 獲取輸入的內容並添加到顯示的頂部 —— 和后續知識掛鈎的重點來了

輸入框組件是App組件的子組件,而數據展示是NameList組件中的NameObj組件,即:現在關系就是如下的樣子

image

上面這種就是不同組件之間的通信情況,現在來了解原生的解決辦法

  1. 原生的不同組件通訊
  • App.vue是大哥,用它做文章,這樣就變成了App這個父組件和輸入框以及Namelist這兩個子組件之間的關系了

  • 第一步:將data搬到App組件中去並傳給NameList數據展示組件

image

然后NameList數據顯示區再傳給數據顯示組件

image image

這樣父傳子、子傳孫....這樣就串通一條路了( 即:下圖右邊部分 )

image

第二步:將輸入框組件中的數據收集起來,並傳給父組件( 這就是子傳父 )

image image

將數據傳給父組件 —— 開始子傳父

子傳父的技巧就是:父組件傳給子組件一個函數( props的變樣版,傳的不是對象、key-value,而是整一個函數傳過去 )、然后子組件利用props接收到函數之后調用一下( 把傳遞數據當做參數 ),那么父組件中的函數的參數就是要傳遞的數據了

image image

上圖id是使用random()生成的隨機數啊,這有弊端的,數字有窮盡的時候,所以:嚴格來說用uuid、身份證號、電話號碼......作為id最好

image
  1. 將子組件傳遞的數據添加到數據欄的頂部去
image image
2.3.8.4、交互編寫
  1. 實現選擇和數據的改變
image
  • 1)、最簡單粗暴的方式 —— 但是:不建議用

    image image image

    成功是成功了,但是:說了不建議用,因為:這種方式違背了Vue的設計( 但是:開發中又喜歡用,簡單實用嘛 )

    • 違背了Vue的設計是因為:props在底層是被檢測了的,Vue不支持去修改它的東西,但是:按上述的方式做了之后,卻會發現:並不會報錯,這是因為:修改的是值和對象的區別

      image
  • 2)、按照邏輯老實編寫

    • 這種實現方式的思路就是:在頁面中點擊 / 改變選擇框時,拿到這條數據的id,然后利用id去所有的數據中遍歷,找到對應的這條數據,最后改變這條數據isCheck的值即可

    • 下面的操作也是一個父傳子的使用過程:這里有一句話:數據在哪里,對數據的操作( methods )就在哪里

      image image image image

2、實現每條數據的刪除功能

  • 1)、先把樣式解開,讓鼠標懸浮時刪除按鈕可見

    image image
  • 2)、實現數據與刪除按鈕交互( 還是子傳父的套路 )

    實現邏輯簡單:拿到要刪除數據的id,然后去眾多數據中把要刪除數據給過濾掉不顯示即可( 邏輯刪除 )

    image image image image

3、實現底部的已選擇人數和總計人數功能

3.1、最原生的方式

  • 1)、父傳子 —— 傳遞persons這個數據

    image image

3.2、使用數組的reduce()這個API,這個API專做數據統計的

  • 認識一下reduce()

    image image
    • reduce()最終的返回值是:程序執行的最后一次的nextValue值
  • 使用reduce()實現功能

    image image

接下來就只剩下底部的全選和清除已選這兩個功能了

4、實現全選交互和清除已選人員功能

4.1、實現全選交互( 子傳父 + 計算屬性使用技巧 )

image image image image image

上面這個全選使用分步利用子傳父實現每一步也是可以的,只是有點復雜罷了

4.2、清除已選人員

  • 這個的思路更簡單了,就是查看頁面中的數據哪些的isCheck為true,然后過濾掉這些數據即可( 實現方式一樣簡單,也是子傳父 )

    image image
2.3.8.5、組件化開發流程總結

組件化編寫流程

  1. 拆分靜態組件:組件要按照功能點拆分,命名不要和HTML元素名沖突

  2. 實現動態組件:考慮好數據的存放位置,數據是一個組件在用,還是一些組件在用

  • 一個組件在用:把數據放到組件自身即可

  • 一些組件在用:把數據放到它們共同的父組件上【 這也叫狀態提升 】

  • 3、實現交互:從綁定事件開始

props配置總結:適用於以下過程

  1. 父組件 ——> 子組件 通信

  2. 子組件 ——> 父組件 通信

v-model總結

  • 使用v-model時要切記:v-model綁定的是值,但是:這個值不能是props中傳遞過來的值,因為:props底層被Vue監測了的,不允許修改

    注:props中傳過來的若是對象類型的值時,雖然修改"對象中的屬性"時Vue不會報錯,但是:不建議用


2.3.9、下一篇鏈接

鏈接:https://www.cnblogs.com/xiegongzi/p/15875808.html



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM