Vue2和Vue3技術整理2 - 核心篇 - 更新完畢

紫邪情發表於2022-02-03

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



元件小結

  • Vue中使用元件的三板斧
    • 1、建立元件
    • 2、註冊元件
    • 3、使用元件( 寫元件標籤即可 )
  • 如何定義一個元件?
    • 使用Vue.extend( { options } )建立,其中options 和 new Vue( { options } )時傳入的哪些option“幾乎一樣”,區別就是:
      • 1、el不要寫 ——— 因為最終所有的元件都要經過一個vm的管理( 根元件 ),由vm中的el決定服務哪個容器
      • 2、data必須寫成函式式 ———— 因為可以避免元件被複用時,資料存在引用關係
      • 另外:template選項可以配置元件結構
  • 如何註冊元件?
    • 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: '女'
                  }
              }
          }
    
    
  • 上面兩種都可以

    • image
    • image
    • 但是:簡寫形式在底層其實也呼叫了Vue.extend()
    • image
    • image
    • 驗證完了,記得把原始碼的斷點去掉


2、元件名的問題

  • (1)、元件名為一個單詞時
    • 使用全小寫字母 / 首字母大寫都沒問題
      • image
      • image
  • (2)、元件名為多個單片語成時
    • 全部用小寫 / 使用 - 進行分割都沒問題( 此種分割需要注意在註冊時的方式,加單引號 )
      • image
      • image
    • 還有一種就是上圖中的效果:大駝峰命名
      • image
      • image
      • 但是:這種大駝峰命名需要注意,有些人就不可以( 因為:嚴格來說這種命名是後續的技術 —— 使用腳手架時的方式 ),但是:有些人又可以,而且不報錯,比如我上圖中的效果,因為這是Vue版本的問題【 最近才下的Vue的話,是新的,此種命名方式就是可以的,但是:在還沒接觸腳手架之前可以測試玩,先別正式用啊 】,要看原始碼的話,從下圖這裡往後看即可
        • image
    • (3)、注意元件名別和HTML中的原生標籤名一致,會衝突報錯,HTML的限制就是上圖中看原始碼中的哪些( 別想著它是小寫,你搞大寫,也是不行的^ _ ^ ),如果非要用HTML標籤名,讓人見名知意,那就在原生HTML標籤名前加一些特定的詞,如:user-input這種【 一般加的字首都是功能點名稱 】,記得千萬別用:input、h2....此類名字來命名元件名


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

  • (1)、可以使用開放標籤,如:<my-info></my-info>,這種肯定沒任何問題
  • (2)、也可以使用自閉合標籤,如:<my-info/>,但是這種有坑,這種使用方式需要腳手架支援,否則渲染時會出問題
    • 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容器使用的元件標籤 ),Vue就會去幫忙建立對應的元件,呼叫了建構函式,怎麼呼叫的?new出來的嘛,所以:這兩個元件物件肯定不一樣( 前面先驗證是否一樣就是為了注意這點,看起來一樣,實質不一樣 ,每個元件建立的都是全新的VueComponent(),得到的是一個全新的物件Sub )
        • 同時上面說到,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的後代 )
    • vm和vc之間很多東西只是複用了而已- ( 這裡說的複用,裡面有大門道,vm和vc之間是有關係的,這裡需要原型物件知識 —— 就一句話:函式肯定有prototype( 顯示原型屬性 ),而例項( 如:const person = vue.extend()中的person )肯定有 _ _proto _ _ ( 隱式原型屬性 ),而這二者指向的是同一個物件:即,該例項的原型物件,而vc和vm之間就是通過這二者關聯起來的
  • vm和vc之間的內建關係是:VueComponent.prototype._ _proto _ _ === Vue.prototype【這句話的驗證自行在控制檯輸出檢視,答案是:true】

    • 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>
      <!-- 3、使用app管理的元件 -->
      <person></person>
  </div>
</template>

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

    export default {
        name: 'App'
        // 2、註冊引起來的元件
        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
      • image
    • 2、但是:引入main.js,去main.js裡面開始解析時,發現:需要引入App.vue,所以:接著引入App.vue
      • image
    • 3、進入App.vue,又發現需要引入Person.vue
      • image
    • 4、將所有東西都引入完了之後,就可以依次進行渲染了( 邏輯就不說明了 ),而經過上面的邏輯梳理之後會發現:main.js就是入口,是從main.js開始引入,從而把其他的東西也給引入進來了


當然:以上的東西弄完之後,還啟動不了,一啟動就會報錯

  • image
  • 這是因為:瀏覽器不能解析ES6語法,這需要使用另外一個技術,腳手架來支援



2.3.2、認識腳手架 vue cli
  • cli全稱: command line interface 即:命令列介面工具,但是:一般說的都是腳手架,正規名字說起來太官方、繞口

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

    • image


2.3.2.1、使用nodejs配置腳手架
  • 前提:保證自己的電腦有nodejs,玩後端的人要是不瞭解nodejs的話,就把它理解為伺服器,低配版的tomcat,
  • nodejs的配置很簡單,官網進行下載、一直next
    • 有個注意點:選擇安裝目錄時,別把nodejs安裝到系統C盤了,不然很大可能出現許可權不足,無法操作的問題,特別是:如果自己的電腦沒升級,還是家庭版的而不是專業版的,這種問題更常見
      • 出現這種問題就需要切換到管理員身份執行cmd才可以進行安裝vue-cli了,甚至有時會奇葩點:需要在管理員身份下執行npm clean cache –force
      • 然後再進入到C盤的使用者目錄下的appdata/roaming下把一個叫做npm-cache的快取檔案刪了,最後再用管理員身份執行npm clean cache –force清除快取【 當然:npm clean cache –force不是絕對好用,還得看自己的另外配置 不多延伸了 】,經過上面的操作,把自己整瘋了之後才可以安裝vue cli腳手架


  • nodejs官網:https://nodejs.org/en/download/
    image

  • LTS就是穩定版,而CURRENT就是更新版( 新特性就丟在這裡面的,可能會出現bug,所以不推薦下載 )

    • 其中下載msi和zip都可以,區別就是msi是直接幫你把環境變數配好了的,當然:也有其他的區別,而zip就是解壓之後,自己進到目錄下複製路徑,然後配置在“系統環境變數”的path目錄中即可,這些操作玩java的第一天就弄了jdk的環境變數,所以再熟悉不過了,而如果是前端人員,nodejs早學了,所以可以下滑到到後面全域性安裝vue cli那裡,安裝成功之後是如下效果

      • image

      • 檢視一下是否成功?

        • 進入dos視窗( win+r,輸入cmd回車 )

        • image

        • 表明成功

        • 但是:現在npm的配置和快取檔案都在C盤使用者目錄/appdata/roaming/npm 和 appdata/local/npm-cache中的

        • image

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

          • 1、在安裝的nodejs中新建node_global和node_cache兩個資料夾( 前為全域性配置路徑,後為npm快取路徑 )

            • image
          • 2、執行如下命令( 路徑記得複製成自己的 ),另外記得用管理員許可權開啟命令列視窗

            • 進行設定
              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
          • 3、修改環境變數( 後端人員再熟悉不過,如果前端人員不明白的,直接計算機右鍵,選擇屬性,選擇高階系統設定,選擇環境變數就可以了【家庭版和專業版、win10和win7不一樣,自行查詢】 )

            • 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 install -g @vue/cli
    • npm 是nodejs的指令 拉取了淘寶映象之後,就可以使用cnpm代替了
    • install 就是安裝的意思
    • -g 是全域性安裝
    • @vue/cli 是安裝的東西
    • 有個注意點:要是有人知道可以使用npm install -g vue-cli這樣安裝腳手架的話,可以用,沒錯的,但是:目前別這麼安裝( 它安裝的腳手架是舊版本的,用這種方式安裝的不能保證vue( 目前版本是1 — 3 )和vue-cli( 目前版本是1 — 4 )的版本很適合,所以後續使用一些命令時可能會出現版本不足的問題,讓把版本升級,而使用@vue/cli安裝的是最新版本
    • 對於後端人員來說,這些指令太簡單了,所以後續不說明了,下圖是我重新安裝了一次的結果
      • image


  • 2、建立一個資料夾,並進入目錄中,使用指令:vue create xxxx
    • vue create 是cli3.x的命令,要是前面安裝腳手架時是亂整的,就會發現:這個命令用不了,要是出現這樣的話,那麼執行一遍這個命令,會提示你:解除安裝以前的cli,然後執行什麼命令安裝cli
    • xxx 就是要建立的專案名
      • image
      • image
      • image
      • 出現如上圖就說明在開始拉取依賴了


  • 3、啟動專案
    • image
    • image
    • image
    • 想要退出啟動的程式,一是直接點視窗右上角的×,二是按兩次ctrl+c即可



2.3.2.2、分析cli構建的專案
  • 使用vscode開啟剛剛編譯的專案【 ps:有些人是個人才,開啟還整半天,1資料夾右鍵有一個open with code / 使用code開啟,圖示就是vscode的,沒有的話,是安裝vscode時,有一個介面是open with xxxx 的兩個選擇框沒選,解除安裝、重灌把那兩個√打上就可以了 】

image



1、packpage-lock.json

image



2、package.json

image




  • 以上就是基礎的東西,接下來就對照前面手寫的單檔案元件思路來分析接下來的東西,那時說過:main.js是入口,所以cli腳手架程式就從main.js入手( 在cli中為什麼它是入口?腳手架底層做的處理 )
    • 1、main.js
      • image
    • 2、引入了App.vue元件,那就接著分析App.vue元件
      • image
      • 注意:
        • assets目錄是專門用來放靜態資源的,如:png、mp3...( 後端的人就把這個目錄當做是SpringBoot中的那個static目錄 )
        • components目錄是專門用來放元件的( App.vue是一人之下【vm】萬人之上【其他任何元件】,所以不在這裡面 )
    • 3、上面引入了helloword元件,而那裡面就是一堆正常的元件寫法
    • 4、分析的差不多了,但是:還少了一個重要的東西,容器在哪裡?
      • 就在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()函式實現模板解析器的效果


  • 1、使用包含模板解析器的vue最簡單
    • 引入的vue有問題,那就改一下嘛
      • image
      • image


  • 2、使用render()函式來實現解析template的功能
    • image
    • image
    • 知道了render()的結構,那就去實現解析template的功能
      • image
      • 然後蘭姆達表示式簡寫不就成原來的樣子了嗎
        • image
        • App就是h2,因為:App是一個元件,使用時就是<App/><App><App>
        • 這個render()函式也就在vm繫結容器時會用到,其他地方見都見不到的



2.3.2.4、關閉語法檢測
  • 官網中有,改cli的全域性配置也是一樣的套路

image



  • 官網裡面就是說新建一個vue.config.js的檔案,這個檔案必須和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中不可以說:不用了加個註釋,然後等後面用的時候再解開註釋,這種是不行的,要麼就配置,要麼就不配置,否則:啟動不了專案



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、只接收資料

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>



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>



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
  • 2、在需要的元件中引入抽取的程式碼和利用mixins配置進行使用
    • image
  • 3、執行效果
    • image


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

  • 1、除了生命週期,如果其他配置是在mixin中定義了,同時在元件中也定義了,那麼:優先使用的是元件中自己定義的( 無論二者相同與否都一樣 )
    • image
    • image
  • 2、如果在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:{........},
          		........
            }
        
    • 2、在需要的元件中引入混入

    • 3、使用混入,如:

      • 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


2、在main.js中引入、使用外掛

  • image


3、效果如下

  • image
  • 可以得知:建立的外掛中傳遞的那個引數Vue就是vm( Vue例項物件 )的締造者 —— vue建構函式
  • 得到上面哪那個結果就很重要了,試想:我們使用這個建構函式做過什麼事?
    • 自定義全域性指令 Vue.directive
    • 定義全域性過濾器 Vue.filter
    • 定義全域性混入 Vue.mixin
    • ........
  • 把這些東西放到建立外掛的install()中可行?它接受的引數就是Vue嘛


正宗玩法

  • 1、建立包含install()方法的物件的js檔案
    • image
  • 2、在main.js中引入外掛、應用元件
    • image
  • 3、使用外掛中的東西
    • image
  • 4、效果如下:
    • 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( ....... )
                .........
            }
        }
        
        
    • 2、在main.js中引入外掛

    • 3、在main.js中向Vue應用外掛 Vue.use( 外掛名 )

    • [ 4、使用外掛中定義的東西 ] ———— 可有可沒有,看自己的程式碼情況

    • 這裡注意一個東西:定義外掛中的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



2、獲取輸入的內容並新增到顯示的頂部 —— 和後續知識掛鉤的重點來了

  • 輸入框元件是App元件的子元件,而資料展示是NameList元件中的NameObj元件,即:現在關係就是如下的樣子
    • image
    • 上面這種就是不同元件之間的通訊情況,現在來了解原生的解決辦法



3、原生的不同元件通訊

  • 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



4、將子元件傳遞的資料新增到資料欄的頂部去

  • 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、下一篇連結

相關文章