vue.js 学习笔记(二)组件化开发

vue.js 学习笔记(二)组件化开发

文章目录

  • vue.js 学习笔记(二)组件化开发
  • 一、组件化开发
    • 1.1 组件使用的基本步骤
      • (1)Vue.extend()
      • (2)Vue.component()
      • (3)使用组件
    • 1.2 全局组件和局部组件
    • 1.3 父组件和子组件
    • 1.4 语法糖(重要,之前的写法现在不用了)
      • 1.4.1 注册全局组件
      • 1.4.2 注册局部组件
    • 1.5 组件模板的分离写法
    • 1.6 组件访问vue的数据
      • 1.6.1 组件自己数据的存放
    • 1.7 父子组件的通信
      • 1.7.1 父子组件通信的方法
      • 1.7.2 props基本用法(父组件向子组件传递信息)
        • 1. 静态props
        • 2. 动态props
        • 3. props值的两种表达形式
        • 4. props中的命名约定
        • 5. props验证
      • 1.7.3 子传父
    • 1.8 父子组件的访问方式
      • 1.8.1 父组件访问子组件
      • 1.8.2 子组件访问父组件

一、组件化开发

       组件化开发的思想:将复杂的问题拆分成很多小问题。若我们将页面中所有的逻辑处理全部放在一起,处理起来会非常复杂,且不利于后续的管理和扩展。若我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护都会变得容易

       

1.1 组件使用的基本步骤

组件的使用的三个步骤:(Vue 2.x开始实际上就不用,只是是基础)

  • 创建组件构造器:调用Vue.extend()
  • 注册组件:调用Vue.component()
  • 使用组件:在Vue实例作用范围内使用
vue.js 学习笔记(二)组件化开发_第1张图片

       

(1)Vue.extend()

  • 调用Vue.extend()创建的是一个组件构造器
  • 通常在创建构造器时,传入的template代表我们自定义组件的模板,该模板就是在使用组件的地方,要显示的HTML代码

(2)Vue.component()

  • 将刚才的组件构造器注册为一个组件,并给他起一个组件的标签名称
  • 传递的参数:注册组件的标签名和组件构造器

(3)使用组件

​ 组件必须挂载在某个Vue实例下,否则起不生效

vue.js 学习笔记(二)组件化开发_第2张图片

       

1.2 全局组件和局部组件

// 注册组件(全局组件,意味着可以在多个Vue实例下使用)
Vue.component('cpn',cpnC); //全局组件

const app = new Vue({
     
    el:'#app',
    data: {
     
        message:'你好'
    },
    components: {
     
        //cpn使用组件时的标签名
        cpn: cpnC //局部组件
    }
})

       

1.3 父组件和子组件

// 创建第一个组件构造器(子组件)
const cpnC1 = Vue.extend({
     
    template:`
        

xxxx

hhhh

`
}); // 创建第二个组件构造器(父组件) const cpnC2 = Vue.extend({ template:`

xxxx

hhhh

`
, components: { cpn1: cpnC1 } }); // root组件 const app = new Vue({ el:"#app", data: { message: '你好啊' }, components: { cpn2: cpnC2 } })

       

1.4 语法糖(重要,之前的写法现在不用了)

1.4.1 注册全局组件

Vue.component('cpn1',{
     
    template:`
        

xxxx

hhhh

`
});

注意:cpn1用单引号或双引号包裹的

       

1.4.2 注册局部组件

const app = new Vue({
     
    el:"#app",
    data: {
     
        message: '你好啊'
    },
    components: {
     
       'cpn2': {
     
           template:`
              

xxxx

hhhh

`
} } })

注意:cpn2用单引号或双引号包裹的

       

1.5 组件模板的分离写法


<script type="text/x-template" id="cpn">
    <div>
      <h2>xxxx</h2>
      <p>hhhh</p>
    </div>
script>

// 注册全局组件
<script>
    Vue.component('cpn', {
       
      template: '#cpn'
    })
script>

       

1.6 组件访问vue的数据

  • 组件是一个单独功能模块的封装,这个模块有个属于自己的HTML,也应该有属性自己的数据data
  • 组件不能直接访问Vue实例中的data

1.6.1 组件自己数据的存放

  • 组件对象也有data属性(也可以有methods等属性),但该data属性必须是一个函数,即data(),原因:函数返回自己的对象,相互之间不会互相影响。
  • 该函数返回一个对象,对象内部保存着数据
<div id="app">
    <my-cpn>my-cpn>
div>

<template id="myCpn">
    <div>消息:{
    {message}}div>
template>

<script>
    const app = new Vue({
       
        el:"#app",
        components: {
       
            'my-cpn': {
       
                template: "#myCpn",
                data() {
       
                    return {
       
                        message: 'hello world'
                    }
                }
            }

        }
    })
script>

       

1.7 父子组件的通信

       背景:我们知道组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据或是Vue实例数据的。 但在开发中,往往会有一些数据需要从上层传递到下层的,如:在页面中,从服务器请求到了很多数据,其中一部分数据并非是整个大组件来展示的,而是需要下面的子组件来展示。这时并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)

1.7.1 父子组件通信的方法

  • 父组件通过 props 向子组件传递数据
  • 子组件通过事件 events 向父组件发送信息
  • 总结: props down, events up
vue.js 学习笔记(二)组件化开发_第3张图片

       

1.7.2 props基本用法(父组件向子组件传递信息)

父组件向子组件传递数据分为两种方式:动态和静态

1. 静态props

       子组件要显式地用 props 选项声明它期待获得的数据,静态 Props 通过为子组件在父组件中的占位符添加特性的方式来达到传值的目的

<div id="app">
    <child-cpn :message="message">child-cpn>
div>

<template id="childCpn">
    <div>消息:{
    {message}}div>
template>

<script>
    const app = new Vue({
       
        el:"#app",
        data: {
       
            message: 'hello'
        },
        components: {
       
            'child-cpn': {
       
                template: "#childCpn",
                props: ['message']
            }

        }
    })
script>

props传递的过程:

  1. Vue实例中初始化data
  2. 子组件中初始化props
  3. 通过:message="message"将data中的数据传给了props(双引号中的message才是绑定的数据变量)
  4. 将props中的数据显示在子组件中
vue.js 学习笔记(二)组件化开发_第4张图片

       

2. 动态props

       在模板中,要动态地绑定父组件的数据到子模板的 props,与绑定到任何普通的HTML特性相类似,就是用 **v-bind。**每当父组件的数据变化时,该变化也会传导给子组件

vue.js 学习笔记(二)组件化开发_第5张图片

       

3. props值的两种表达形式

  • 字符串数组:数组中的字符串就是传递时的名称
const cpn = {
     
    template: '#cpn',
    props:['cmovies','cmessage']
}
  • 对象:对象可以设置传递时的类型,也可以设置默认值等
const cpn = {
     
    template: '#cpn',
    props: {
     
        // 1.类型限制
        // cmovies: Array,
        // cmessage: String
        
        //2.或提供一些默认值
        cmessage: {
     
            type: String,
            default: 'hhhhh',
            required: true  //意味着必须传值,否则报错
        }
        // 类型是对象或数组时,默认值必须是一个函数
        cmovies: {
     
        	type: Array,
            default() {
     
				return []
            }
    	}
    }
}

       

4. props中的命名约定

  • 对于props声明的属性来说,在父级HTML模板中,属性名需要使用中划线写法,不支持驼峰
var parentNode = {
     
  template: `
  
`
, components: { 'child': childNode } };
  • 子级props属性声明时,使用小驼峰或者中划线写法都可以;而子级模板使用从父级传来的变量时,需要使用对应的小驼峰写法
var childNode = {
     
  template: '
{ {myMessage}}
'
, //子级模板使用从父级传来的变量:使用小驼峰写法 props:['myMessage'] // 子级props属性声明时,使用小驼峰或者中划线写法都可以 // 或者 props:['my-message'] }

       

5. props验证

对 props 进行类型等验证时,需要用对象写法

验证支持的数据类型有:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

当有自定义的构造函数时,也支持自定义的类型

Vue.component('my-component', {
     
    props: {
     
        //基础的类型检查(‘null’匹配任何类型)
        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;
            } 
        }
    }
})

       

1.7.3 子传父

方法:通过自定义事件来完成

自定义事件的流程:

  • 子组件中,通过 $emit() 来触发事件
  • 父组件中,通过 v-on (@)来监听子组件事件

<div id="app">
    <cpn @itemClick="cpnClick">cpn> // 监听到子组件事件:itemClick后触发cpnClick事件
div>


<template id="childCpn">
    <div>
        <button v-for="item in cactegories"
                @click="btnClick(item)">
            {
    {item.name}}
        button>
    div>
template>

<script>
    // 子组件
    const cpn = {
       
        template: '#cpn',
        data() {
       
            return {
       
                categories:[
                    {
       id: 'aaa', name: '1'},
                    {
       id: 'bbb', name: '2'},
                    {
       id: 'ccc', name: '3'},
                    {
       id: 'ddd', name: '4'}
                ]
            }
        },
        methods: {
         // 子组件的自定义事件
            btnClick(item) {
       
                // 发射事件
                this.$emit('item-click',item)
            }
        }
    }

    // 父组件
    const app = new Vue({
       
        el:"#app",
        data: {
       
            message: 'hello'
        },
        components: {
       
            cpn
        },
        methods: {
        //父组件接收事件
            cpnClick(item) {
       
                console.log('cpnClick');
            }
        }
    })
script>
vue.js 学习笔记(二)组件化开发_第6张图片

       
案例:实现两个按钮+1和-1,点击后修改counter。操作过程在子组件中完成,展示交给父组件,就需要把子组件中的counter传给父组件的某个属性,如total

<div id="app">
    <cpn :number1="num1"
         :number2="num2"
         @num1change="num1change"
         @num2change="num2change">
    cpn>
div>


<template id="cpn">
    <div>
        <h2>props:{
    {number1}}h2>
        <h2>data:{
    {dnumber1}}h2>
        <input type="text" v-model="dnumber1">
        <h2>props:{
    {number2}}h2>
        <h2>data:{
    {dnumber2}}h2>
        <input type="text" v-model="dnumber2">
    div>
template>

<script>
    // 子组件
    const cpn = {
       
        template: '#cpn',
        data() {
       
            return {
       
               dnumber1:this.number1,
               dnumber2:this.number2
            }
        },
        methods: {
         // 子组件的自定义事件
            num1Input(event) {
       
                //将input中的value赋值到dnumber中
                this.dnumber1 = event.target.value;
                this.$emit('num1change',this.dnumber1)
                this.dnumber2 = this.dnumber1 *100;
                this.$emit('num2change',this.dnumber2)
            }
            num2Input(event) {
       
                //将input中的value赋值到dnumber中
                this.dnumber2 = event.target.value;
                this.$emit('num2change',this.dnumber2)
                this.dnumber2 = this.dnumber2 /100;
                this.$emit('num1change',this.dnumber1)
            }
        }
    }
	// 或者用watch监听属性的变化
     const cpn = {
       
        template: '#cpn',
        data() {
       
            return {
       
               dnumber1:this.number1,
               dnumber2:this.number2
            }
        },
        watch: {
       
            dnumber1(newvalue) {
       
                this.dnumber2 = newvalue * 100;
                this.$emit('num1change',newvalue);
            },
            dnumber2(newvalue) {
       
                this.dnumber1 = newvalue / 100;
                this.$emit('num2change',newvalue);
            }
        }
    }
    
    // 父组件
    const app = new Vue({
       
        el:"#app",
        data: {
       
            num1:1,
            num2:0
        },
        components: {
       
            cpn: {
       
                template: '#cpn',
                props: {
       
                    number1: Number,
                    number2: Number
                }
            }
        },
        methods: {
       
            num1change(value) {
       
                this.num1 = parseFloat(value)
            },
            num2change(value) {
       
                this.num2 = parseFloat(value)
            }
        }
    })
script>

注意:不要直接去绑定num1,num2 来改变值,改变数据时写一个值

vue.js 学习笔记(二)组件化开发_第7张图片

       

1.8 父子组件的访问方式

  • 父组件访问子组件:使用 $children 或 $refs
  • 子组件访问父组件:使用 ** p a r e n t ∗ ∗ ( 访 问 根 组 件 时 可 用 parent** (访问根组件时可用 parent访root)

1.8.1 父组件访问子组件

this.$children 是一个数组类型,包含所有子组件对象

vue.js 学习笔记(二)组件化开发_第8张图片

 
vue.js 学习笔记(二)组件化开发_第9张图片

       

1.8.2 子组件访问父组件

<template id="cpn">
    <div>
        <h2>hhhh2>
        <button @click="btnClick">button>
    div>
template>

<script>
    const app = new Vue({
       
		el:"#app",
        data:{
       
            message:'hhh'
        }
        components: {
       
            cpn: {
       
                template: '#cpn',
                data() {
       
                    return {
       
                        name:'我是cpn组件的name'
                    }
                },
                components: {
       
                    ccpn: {
       
                   		template: "#ccpn",
                        methods: {
       
                            btnClick() {
       
                                //1. 访问父组件$parent
                                console.log(this.$parent);
                                console.log(this.$parent.name);
                                
                                //2. 访问根组件$root
                                console.log(this.$root);
                                console.log(this.$root.message);
                            }
                        }
                    }
           		}
            }
        }
    })
script>

你可能感兴趣的:(Vue,vue.js,javascript,前端)