IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue.js 学习笔记(二)组件化开发 -> 正文阅读

[JavaScript知识库]vue.js 学习笔记(二)组件化开发

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

一、组件化开发

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

???????

1.1 组件使用的基本步骤

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

  • 创建组件构造器:调用Vue.extend()
  • 注册组件:调用Vue.component()
  • 使用组件:在Vue实例作用范围内使用

???????

(1)Vue.extend()

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

(2)Vue.component()

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

(3)使用组件

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

???????

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:`
        <div>
            <h2>xxxx</h2>
            <p>hhhh</p>
        </div>
	`
});

// 创建第二个组件构造器(父组件)
const cpnC2 = Vue.extend({
    template:`
    <div>
        <h2>xxxx</h2>
        <p>hhhh</p>
        <cpn1></cpn1>
    </div>
    `,
    components: {
        cpn1: cpnC1
    }
});

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

???????

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

1.4.1 注册全局组件

Vue.component('cpn1',{
    template:`
        <div>
            <h2>xxxx</h2>
            <p>hhhh</p>
        </div>
	`
});

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

???????

1.4.2 注册局部组件

const app = new Vue({
    el:"#app",
    data: {
        message: '你好啊'
    },
    components: {
       'cpn2': {
           template:`
              <div>
                 <h2>xxxx</h2>
                 <p>hhhh</p>
              </div>
           `
       } 
    }
})

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

???????

1.5 组件模板的分离写法

<!-- 1.script标签,注意类型必须是text/x-template -->
<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

???????

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. <child-cpn :message="message"></child-cpn> 通过:message="message"将data中的数据传给了props(双引号中的message才是绑定的数据变量)
  4. 将props中的数据显示在子组件中

???????

2. 动态props

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

???????

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: `
  <div class="parent">
    <child my-message="aaa"></child>
    <child :my-message="message"></child>
  </div>`,
  components: {
    'child': childNode
  }
};
  • 子级props属性声明时,使用小驼峰或者中划线写法都可以;而子级模板使用从父级传来的变量时,需要使用对应的小驼峰写法
var childNode = {
  template: '<div>{{myMessage}}</div>',  //子级模板使用从父级传来的变量:使用小驼峰写法
  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>

???????
案例:实现两个按钮+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 来改变值,改变数据时写一个值

???????

1.8 父子组件的访问方式

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

1.8.1 父组件访问子组件

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

?

???????

1.8.2 子组件访问父组件

<template id="cpn">
    <div>
        <h2>hhh</h2>
        <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>

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-24 14:50:47  更:2021-10-24 14:53:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 14:52:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码