• 03vue组件化


    vue组件

    1.vue组件三板斧

    1.创建组件构造器对象
    2.注册组件
    3.使用组件

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<!-- 3.使用组件 -->
    			<my-cpn></my-cpn>
    			<h1>***</h1>
    			<cpnc></cpnc>
    			<cpnc2></cpnc2>
    
    		</div>
    
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		<script>
    			//1.创建组件构造器的对象
    			const cpnc = Vue.extend({
    						template: `
    				        <div>
    				          <h2>标题:我是cpnc组件</h2>
    				          <p>内容1...</p>
    				          <p>内容2...</p>
    				        </div>`,
    			})
    			
    			const cpnc2 = Vue.extend({
    						template: `
    				        <div>
    				          <h2>我是cpnc2组件</h2>
    				          <p>内容1...我是一个局部组件</p>
    				          <p>内容2...</p>
    				        </div>`,
    			})
    			
    			//2.全局注册组件
    			Vue.component('my-cpn', cpnc)
    			
    			const app = new Vue({
    				el:"#app",
    				components:{
    					//局部组件创建
    					cpnc:cpnc,
    					cpnc2:cpnc2,
    				}
    			})
    		</script>
    
    	</body>
    </html>
    

    组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 my-cpn。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用: <my-cpn></my-cpn>

    2.vue 全局组件和局部组件

    全局组件,可以在多个vue实例中使用,类似于全局变量。

    使用Vue.component('my-cpn', cpnc)方式注册,直接使用``调用。my-cpn是全局组件的名字,cpnc是定义的组件对象。

    局部组件,只能在当前vue实例挂载的对象中使用,类似于局部变量,有块级作用域。

    使用方式与全局变量一样,直接使用<cpnc></cpnc>调用。cpnc:cpnc第一个cpnc是给组件命名的名字,第二个是定义的组件对象。如果俩个同名也可以直接使用es6语法:

    components:{//局部组件创建
            cpnc
    }
    
    // 注册全局组件(全局组件,可以在多个vue实例中使用)
    Vue.component('my-cpn', cpnc)
    
    // 注册局部组件,components:{cpnc:cpnc}
    const app = new Vue({
          el:"#app",
          components:{//局部组件创建
            cpnc:cpnc
          }
        })
    

    3.vue 父组件和子组件

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>父子组件</title>
    	</head>
    	<body>
    		<div id="app">
    			<!-- 使用组件 -->
    			<cpn2></cpn2>
    		</div>
    		
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		<script>
    			//1.创建组件构造器对象
    			const cpn1 = Vue.extend({
    				template: `
    					<div>
    						<h2>我是子组件1</h2>
    						<p>哈哈</p>
    					</div>`,
    			})
    
    			//2.构建父组件,并使用子组件cpn1
    			const cpn2 = Vue.extend({
    				template: `
    			 		<div>
    			 			<h2>我是父组件</h2>
    			 			<p>哈哈<br>******</p>
    						<cpn1></cpn1>
    			 		</div>`,
    				components:{
    				        cpn1:cpn1
    				      }
    			})
    			
    			const app = new Vue({
    				el:"#app",
    				components:{ //创建局部组件
    					cpn2:cpn2,
    				}
    			})
    		</script>
    	</body>
    </html>
    

    上述代码中定义了两个组件对象cpn1cpn2,在组件cpn2中使用局部组件注册了cpn1,并在template中使用了注册的cpn1,然后在vue实例中使用注册了局部组件cpn2,在vue实例挂载的div中调用了cpn2cpn2cpn1形成父子组件关系。

    注意:组件就是一个vue实例,vue实例的属性,组件也可以有,例如data、methods、computed等。

    4、注册组件的语法糖写法

    <script>
        // 1.注册全局组件语法糖
        Vue.component('cpn1', {
          template:`
            <div>
              <h2>全局组件语法糖</h2>
              <p>全局组件语法糖</p>
            </div>`
        })
    
        const app = new Vue({
          el:"#app",
          components:{//局部组件创建
            cpn2:{
              template:`
            <div>
              <h2>局部组件语法糖</h2>
              <p>局部组件语法糖</p>
            </div>`
            }
          }
        })
      </script>
    

    注册组件时候可以不实例化组件对象,直接在注册的时候实例化。{}就是一个组件对象。

    5. 组件模板的分离写法

    5.1 script标签

    使用script标签定义组件的模板,script标签注意类型是text/x-template

    <!-- 1.script标签注意类型是text/x-template -->
      <script type="text/x-template" id="cpn1">
        <div>
            <h2>组件模板的分离写法</h2>
            <p>script标签注意类型是text/x-template</p>
          </div>
      </script>
    

    5.2 template标签

    ​ 使用template标签,将内容写在标签内。

     <!-- 2.template标签 -->
      <template id="cpn2">
        <div>
          <h2>组件模板的分离写法</h2>
          <p>template标签</p>
        </div>
      </template>
    

    使用分离的模板 ,使用template:'#cpn1'

    const app = new Vue({
          el: "#app",
          components: { //局部组件创建
            cpn1:{
              template:'#cpn1'
            },
            cpn2: {
              template: '#cpn2'
            }
          }
        })
      </script>
      
    //全局组件创建
    Vue.component('cpn1', {
          template:'#cpn1',      
        })
    

    例子:

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<!-- 3.使用组件 -->
    			<cpn1></cpn1>
    			<cpn2></cpn2>
    		</div>
    		
    		<!-- 1.script标签注意类型是text/x-template -->
    		<script type="text/x-template" id="cpn1">
    		  <div>
    		      <h2>组件模板的分离写法</h2>
    		      <p>script标签注意类型是text/x-template</p>
    		    </div>
    		</script>
    		 
    		 <template id="cpn2">
    		    <div>
    		      <h2>组件模板的分离写法</h2>
    		      <p>template标签</p>
    		    </div>
    		  </template>
    		  
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		<script>
    			Vue.component('cpn1', {
    				template:'#cpn1',      
    			})
    			
    			const app = new Vue({
    			      el:"#app",
    			      components:{//局部组件创建
    			        cpn2:{
    						template:'#cpn2'
    					},
    			       }
    			    })
    		</script>
    	</body>
    </html>
    

    6. 组件的数据

    6.1数据存放问题

    前面说过vue组件就是一个vue实例,相应的vue组件也有data属性来存放数据。

    放在主app下面是没有效果的。

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    		    <cpn1></cpn1>
    		 </div>
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		 <script>
    		    const app = new Vue({
    		      el: "#app",
    		      components: { //局部组件创建
    		        cpn1:{
    		          template:'<div>{{msg}}</div>',
    		          data(){
    		            return {
    		              msg:"组件的数据存放必须要是一个函数"
    		            }
    		          }
    		        }
    		      }
    		    })
    		  </script>	
    	</body>
    </html>
    

    template中使用组件内部的数据msg

    6.2 组件data为啥必须是个函数

    组件的思想是复用,定义组件当然是把通用的公共的东西抽出来复用。

    计算器1

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<cpn1></cpn1>
    			<cpn1></cpn1>
    			<cpn1></cpn1>
    		</div>
    
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		<template id="cpn1">
    			<div>
    				当前计数:{{ count }}<br>
    				<button @click="decrement">-</button>
    				<button @click="increment">+</button>
    			</div>
    		</template>
    
    		<script>
    			const app = new Vue({
    						el: "#app",
    						components: { //局部组件创建
    							cpn1: {
    								template: '#cpn1',
    								data() {
    									return{
    										count:0,
    									}
    								},
    								methods:{
    									increment(){
    										this.count++
    									},
    									decrement(){
    										this.count--
    									}
    								}
    							}
    						}
    					})
    		</script>
    	</body>
    </html>
    

    计算器二

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<cpn1></cpn1>
    			<cpn1></cpn1>
    			<cpn1></cpn1>
    		</div>
    
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		<template id="cpn1">
    			<div>
    				当前计数:{{ count }}<br>
    				<button @click="count--">-</button>
    				<button @click="count++">+</button>
    			</div>
    		</template>
    
    		<script>
    			const app = new Vue({
    						el: "#app",
    						components: { //局部组件创建
    							cpn1: {
    								template: '#cpn1',
    								data() {
    									return{
    										count:0,
    									}
    								}
    							}
    						}
    					})
    		</script>
    	</body>
    </html>
    

    计数器1和计数器2本质是一样的,实现计数器的复用,各个计数器互不干扰。

    计数器三,组件共用一个数字

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<cpn1></cpn1>
    			<cpn1></cpn1>
    			<cpn1></cpn1>
    		</div>
    
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		<template id="cpn1">
    			<div>
    				当前计数:{{ count }}<br>
    				<button @click="count--">-</button>
    				<button @click="count++">+</button>
    			</div>
    		</template>
    
    		<script>
    			const obj={
    				count:0
    			}
    			const app = new Vue({
    						el: "#app",
    						components: { //局部组件创建
    							cpn1: {
    								template: '#cpn1',
    								data() {
    										return obj;
    								}
    							}
    						}
    					})
    		</script>
    	</body>
    </html>
    

    计数器3不使用函数data,好像共用一个count属性,而使用函数的data的count是各自用各自的,像局部变量一样有块级作用域,这个块级就是vue组件的作用域。

    我们在复用组件的时候肯定希望,各自组件用各自的变量,如果确实需要都用一样的,可以全局组件注册,也可以是用vuex来进行状态管理。

    7、父子组件通信之父传子

    使用props属性,父组件向子组件传递数据

    静态写法:

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    		    <child message="hello!父传子静态写法"></child>
    		</div>
    		 
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		<script>
    		// 注册
    		Vue.component('child', {
    		  // 声明 props
    		  props: ['message'],
    		  // 同样也可以在 vm 实例中像 "this.message" 这样使用
    		  template: '<span>{{ message }}</span>'
    		})
    		// 创建根实例
    		new Vue({
    		  el: '#app'
    		})
    		</script>
    	</body>
    </html>
    
    动态v-bind props 写法
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    		    <div>
    		      <input v-model="parentMsg">
    		      <br>
    		      <child v-bind:message="parentMsg"></child>
    		    </div>
    		</div>
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		<script>
    		// 注册
    		Vue.component('child', {
    		  // 声明 props
    		  props: ['message'],
    		  // 同样也可以在 vm 实例中像 "this.message" 这样使用
    		  template: '<span>{{ message }}</span>'
    		})
    		// 创建根实例
    		new Vue({
    		  el: '#app',
    		  data: {
    		    parentMsg: '父组件内容'
    		  }
    		})
    		</script>
    	</body>
    </html>
    

    props 属性

    Vue.component('my-component', {
      props: {
        // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
        propA: Number,
        // 多个可能的类型
        propB: [String, Number],
        // 必填的字符串
        propC: {
          type: String,
          required: true
        },
        // 带有默认值的数字
        propD: {
          type: Number,
          default: 100
        },
        // 带有默认值的对象
        propE: {
          type: Object,
          // 对象或数组默认值必须从一个工厂函数获取
          default: function () {
            return { message: 'hello' }
          }
        },
        // 自定义验证函数
        propF: {
          validator: function (value) {
            // 这个值必须匹配下列字符串中的一个
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
          }
        }
      }
    })
    

    综合使用

      <div id="app">
        <cpn :cMovies="movies" :cMessage="message"></cpn>
      </div>
      <template id="cpn">
        <div>
          <ul>
            <li v-for="(item, index) in cmovies" :key="index">{{item}}</li>
          </ul>
          <h2>{{cmessage}}</h2>
        </div>
      </template>
      <script src="../js/vue.js"></script>
    
      <script>
        function Person(firstName,lastName) {
          this.firstName = firstName
          this.lastName = lastName
        }
        // 父传子:props
        const cpn = {
          template: "#cpn",
          // props: ['cmovies', 'cmessage'],//数组写法
          props: { //对象写法
            // 1.类型限制(多个类使用数组)
            // cmovies:Array,
            // cmessage:String,
            // cmessage:['String','Number'],
            // 2.提供一些默认值,以及必传值
            cmessage: {
              type: String,
              default: 'zzzzz',
              required: true //在使用组件必传值
            },
            //类型是Object/Array,默认值必须是一个函数
            cmovies: {
              type: Array,
              default () {
                return [1, 2, 3, 4]
              }
            },
            // 3.自定义验证函数
            // vaildator: function (value) {
            //   //这个传递的值必须匹配下列字符串中的一个
            //   return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
            // }
            // 4.自定义类型
            // cmessage:Person,
          },
          data() {
            return {
            }
          },
          methods: {
    
          },
        };
        const app = new Vue({
          el: "#app",
          data: {
            message: "你好",
            movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
          },
          components: {
            cpn
          }
        })
      </script>
    

    补充:props的驼峰标识

    ​ v-bind是 不支持使用驼峰标识的,例如cUser要改成c-User

    <div id="app">
        <!-- v-bind不支持驼峰 :cUser改成 :c-User-->
        <!-- <cpn :cUser="user"></cpn> -->
        <cpn :c-User="user"></cpn>
        <cpn :cuser="user" ></cpn>
      </div>
      <template id="cpn">
        <div>
          <!-- 使用驼峰 -->
          <h2>{{cUser}}</h2>
          <!-- 不使用 -->
          <h2>{{cuser}}</h2>
        </div>
      </template>
      <script src="../js/vue.js"></script>
      <script>
        // 父传子:props
        const cpn = {
          template: "#cpn",
          props: { //对象写法
            //驼峰
            cUser:Object,
            //未使用驼峰
            cuser:Object
          },
          data() {return {}},
          methods: {},
        };
        const app = new Vue({
          el: "#app",
          data: {
            user:{
              name:'zzz',
              age:18,
              height:175
            }
          },
          components: {
            cpn
          }
        })
      </script>
    

    8、子传父

    子组件向父组件传值,使用自定义事件$emit
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<!-- 父组件 -->
    		<div id="app">
    			<!-- 不写参数默认传递btnClick的item -->
    			<cpn @itemclick="cpnClcik"></cpn>
    
    		</div>
    
    		<!-- 子组件模板 -->
    		<template id="cpn">
    			<div>
    				<button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}</button>
    			</div>
    		</template>
    		<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    		<script>
    			//子组件
    			const cpn = {
    				template: "#cpn",
    				data() {
    					return {
    						categoties: [{
    								id: 'aaa',
    								name: '热门推荐'
    							},
    							{
    								id: 'bbb',
    								name: '手机数码'
    							},
    							{
    								id: 'ccc',
    								name: '家用家电'
    							},
    							{
    								id: 'ddd',
    								name: '电脑办公'
    							},
    						]
    					}
    				},
    				methods: {
    					btnClick(item) {
    						this.$emit('itemclick', item)
    					}
    				},
    			};
    			//父组件
    			const app = new Vue({
    				el: "#app",
    				data() {
    					return {
    					}
    				},
    				methods: {
    					cpnClcik(item) {
    						console.log('cpnClick' + item.name);
    					}
    				},
    				components: {
    					cpn
    				},
    			})
    		</script>
    	</body>
    </html>
    
  • 相关阅读:
    Java_zip_多源文件压缩到指定目录下
    Linux:ps -ef命令
    Linux:find命令中
    String.split()与StringUtils.split()的区别
    StringUtils工具类的常用方法
    Java:substring()
    Java:indexof()
    Linux:grep命令
    12、spring工厂+web前台搭建
    11、redis使用ruby实现集群高可用
  • 原文地址:https://www.cnblogs.com/slzhao/p/13336842.html
Copyright © 2020-2023  润新知