前端vue开发之----vue组件详解(一)

news/2024/7/10 2:05:16 标签: vue, 前端, vue.js, 组件化, javascript

实际应用项目:http://github.crmeb.net/u/long

 

主要内容:

1. 组件的基本使用

2. 全局组件和局部组件

3. 父组件和子组件 

4. 组件语法糖的写法

5. 组件data关联的写法

6. 父子组件的通信


 

组件系统是 Vue 的一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。几乎任意类型的应用界面都可以抽象为一个组件树:

 例如上面页面, 页面整体分为三个部分. 我们可以将每一个部分设计为一个组件. 然后将三个组件组成一个页面. 每一个组件又是由多个小组件构成的. 

组件可以让模块可复用性提高. 是一种提倡的用法

一. 组件的基本使用

构建一个组件分为三个部分:

  1. 定义组件
  2. 注册组件
  3. 使用组件

下面, 我们就从这三个部分来定义一个组件

1. 定义组件

语法: 

Vue.extend({
   template: "" 
})

定义组件使用Vue.extend({})然后在里面定义一个template, 我们看到template的内容是html内容,

为了让html能够按照格式显示, 我们使用``将内容框起来

下面我们来注册一个组件

复制代码

const cpnC = Vue.extend({
    template: `<div>
                <h2>aaa</h2>
                <p>组件内容1</p>
                <p>组件内容2</p>
              </div>`
})

复制代码

2. 注册组件

语法:

Vue.component("组件名称", 组件内容)

我们将上面定义的组件进行注册

// 2. 注册组件
Vue.component('my-first-comp', cpnC)

3. 使用组件

<div id="app">
   <my-first-comp></my-first-comp>
</div>

直接使用组件名即可

完整源码:

复制代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--
    1. 注册组件的基本步骤
-->
    <div id="app">
        <my-first-comp></my-first-comp>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        // 1. 创建组件构造器对象
        /**
         * 调用vue.extend()创建一个组件
         * 传入的template代表我们自定义组件的模板
         * vue2.x以后基本看不到这种写法, 会直接使用语法糖创建, 但原理还是这个.
         *
         * @type {VueComponent|void}
         */
        const cpnC = Vue.extend({
            template: `<div>
                            <h2>aaa</h2>
                            <p>组件内容1</p>
                            <p>组件内容2</p>
                          </div>`
        })

        // 2. 注册组件
        Vue.component('my-first-comp', cpnC)

        var app = new Vue({
            el: "#app",
            data: {
                message: "hello"
            }
        });
    </script>
</body>
</html>

复制代码

 

二. 全局组件和局部组件

1. 全局组件

组件有全局组件和局部组件的概念, 如果将一个组件定义在外部就是全局组件

复制代码

    // 定义一个组件
    const myComp = Vue.extend({
        template: `
            <div>
                <p>你好!!</p>
            </div>
        `
    })
    // 注册组件(这种方式注册的组件是全局组件)
    Vue.component('my-comp', myComp)


    let app = new Vue({
        el: "#app",
        data: {
            message: "hello"
        }
    });

复制代码

第一步: 定义了一个组件

第二步:  注册组件, 在new Vue({})外面注册的, 是全局组件. 

第三步: 调用组件

<div id="app2">
    <my-comp></my-comp>
</div>

以上定义的就是一个全局组件. 全局组件什么概念呢? 也就是说任何一个Vue实例对象都可以使用. 

下面定义了两个Vue对象

复制代码

   let app = new Vue({
        el: "#app",
        data: {
            message: "hello"
        },
        components:{
            app1Comp: app1Comp
        }
    });


    let app2 = new Vue({
        el: "#app2"
    })

复制代码

第一个作用对象是id="app"的div, 第二个作用对象是id="app2"的div

复制代码

<div id="app">
    <my-comp></my-comp>
    <app1-comp></app1-comp>
</div>

<div id="app2">
    <my-comp></my-comp>
    <app1-comp></app1-comp>
</div>

复制代码

我们在里面调用组件, 都可以成功. 

全局组件, 一次注册, 多处调用

2. 局部组件

复制代码

const app1Comp = Vue.extend({
        template: `
            <div>
                <p>只有app1才能使用的组件</p>
            </div>
        `
    })

    let app = new Vue({
        el: "#app",
        data: {
            message: "hello"
        },
        components:{
            app1Comp: app1Comp
        }
    });

复制代码

我们定义了一个appComp的组件, 但是注册的时候, 只注册到了app这个Vue对象里, 那么就只有app能使用,其他vue对象不能使用, 这样的组件就是局部组件.

局部组件, 哪里注册, 哪里调用

三. 父组件和子组件

 

 

 像这种有嵌套关系的组件, 就是父子组件. 

那么父组件和子组件如何定义呢?

首先, 定义了一个组件1--comp1

复制代码

       // 定义组件1
        const comp1 = Vue.extend({
            template: `
            <div>
                <p>组件1</p>
            </div>
            `
        })    

复制代码

 

然后定义了一个组件2---comp2

复制代码

        // 定义组件2
        const comp2 = Vue.extend({
            template: `
            <div>
                <h2>组件2</h2>
                <comp1></comp1>
            </div>
            `,
            components:{ // 局部组件
                comp1: comp1
            }
        })

复制代码

我们发现, 在组件comp2中注册了comp1组件, 这里comp2是父组件, comp1是子组件.

最后我们可以把comp2注册到Vue对象上, 在页面就可以调用了

复制代码

    // vue也是一个组件, 是一个root根组件
        var app = new Vue({
            el: "#app",
            data: {
                message: "hello"
            },
            components:{
                comp2: comp2
            }
        });

复制代码

  vue也是一个组件, 是一个root根组件

 

四. 组件语法糖的写法

vue2之后, 就很少看到Vue.extend({})的写法了, 而是使用语法糖

// 语法糖的写法
Vue.component('comp2', {
    template: '<div><h2>你好, 语法糖写法!</h2></div>'
})

直接注册Vue组件

 但是, 这么写会将html代码和组件纽在一起, 下面就说说如何将组件和模板分开

 

五. 模板和组件分离

我们有单独的方式定义模板代码. 有两种方法

第一种: script写法

    <!-- 第一种方式: 使用script -->
    <script type="text/x-template" id="comp2">
        <div>
            <h2>组件和模板分离的写法1</h2>
        </div>
    </script>

使用script, 需要将type设置为text/x-template. 然后给模板设置一个id, 就代表一个模板了

然后, 注册模板

Vue.component('comp2', {
     template: comp2
})

接下来就可以调用组件了

<div id="app">
    <comp2></comp2>
</div>

第二种: template写法

推荐使用第二种写法

<template id="comp3">
        <div>
            <h3>组件模板分离的第二种写法</h3>
        </div>
    </template>

使用template标签, 并为其定义一个id, 组件的定义是一样的

Vue.component('comp3', {
     template: comp3
})

 

 

五. 组件data关联的写法

组件中如果有变量, 怎么办呢? 我们知道在vue实例中, 变量可以定义在data中, 在组件中也有data属性, 但这个data属性是一个方法

例如: 我们定义了一个组件, 其中有一个变量title

<template id="comp1">
        <div>
            <h2>这是一个组件:{{title}}</h2>

        </div>
    </template>

我们在注册组件的时候, 可以定义一个data函数, 并在返回值输出title属性

复制代码

    Vue.component('comp1', {
            template: comp1,

            data() {
                return {
                    title: 'vue组件'
                }
            }
        })    

复制代码

这样就可以拿到属性的值了. data()方法里面定义一个return返回值, 返回值是一个对象.

这样写有些奇怪是不是? 那为什么要写成方法呢? 

协程组件, 我们的目的是复用, 在多处使用, 如果定义成一个变量值, 在一处修改, 其他调用的的地方也会跟着修改, 这不是我们希望看到的.

而方法是有作用域的, 每一个匿名方法都有自己的地址空间, 所以, 变量是不共享. 达到了相互隔离的目的.

那么, 如果就想共享怎么办呢? , 我们可以将变量提取出来. 如下写法:

复制代码

     // 如何让所有组件共享变量呢
        let shareData = {
            title: "组件共有的title"
        }

        Vue.component('comp2', {
            template: comp2,
            data(){
                return shareData
            }
        })

复制代码

这样每次返回的都是一个地址, 所以, 变量之间是共享的.

六. 父子组件的通信

什么是父子通讯呢? 我们来看看京东官网

 

 

 可以吧这个页面看成是大组件, 里面有4个子组件构成: 上面是导航, 左边是栏目导航, 点击栏目导航右侧跟着变化.

我们来分析一下:

数据是在最外层的data里面, 然后循环遍历获取左侧导航, 当点击左侧导航的时候, 需要将参数传递给父组件, 然后发起新的请求, 在渲染到子组件中.

这就是父子通讯. 

父子通讯分为父传子和子传父两种方式

1. 父传子组件的通讯

父子通讯有两种方式: 一种是数组, 一种是对象

我们在vue对象中定义了两个属性: message和languages

复制代码

    let app = new Vue({
            el: "#app",
            data: {
                message: "父元素传递值给子元素111",
                languages:["go", "php", "python", "java", "c语言"]
            }
        });

复制代码

然后要在模板中使用这两个属性, 要怎么样才能拿到属性呢? 

在模板中使用props来接收属性, 使用props接收属性有两种方式:

1) 父子通讯方式---数组方式

第一种是使用数组的方式. 我们在数组中定义两个变量来接收Vue对象中的两个属性.

     Vue.component("comp1", {
            template: "#comp1",
            props:["clanguages", "cmessage"]
        })

然后, 在模板里怎么写呢? 如下:

复制代码

    <template id="comp1">
        <div>
            <p>{{cmessage}}</p>
            <ul>
                <li v-for="item in clanguages">{{item}}</li>
            </ul>
        </div>
    </template>

复制代码

接下来绑定组件变量和vue对象变量的关系, 在哪里调用组件, 就在哪里绑定

 <div id="app">
   <comp1 :clanguages="languages" :cmessage="message"></comp1>
 </div>

绑定的时候其实使用的是v-bind. 将组件的属性clanguage绑定到vue对象, 可以这么写:

:clanguages="languages"

这样就完成了绑定

其实总结有三步骤:

1. 在vue对象中定义属性

2. 在模板组件中定义与vue属性接收的变量

3. 在模板中绑定他们之间的关系

2) 父子通讯方式---对象方式

除了使用数组的方式来接收, 还可以使用对象的方式来接收

复制代码

       // props的对象写法
        Vue.component('comp2', {
            template: "#comp2",
            props:{
                clanguages: {
                    type: Array, // 设置传值的类型必须是数组类型
                    default: [], // 默认值是空数组
                    required: true // 如果设置为true, 这个值必须传, 如果不传将报错
                },
                cmessage: {
                    type: String,
                    default: "aa",
                    required: true
                }
            }
        })

复制代码

props接收的是一个对象, clanguages对象里面可以定义接收数据有三种

  1. 类型type,
  2. 默认值default
  3. 是否是必须有这个属性required: 这个属性的含义是, 调用了组件必须要使用这个属性.

其他使用方法可以参考文章: https://www.cnblogs.com/em2464/p/10418820.html 

2. 子传父自定义事件

父传子使用的是定义属性接收, 而子传父使用的是定义事件的方式.

就使用上面的例子, 点击类型传参给父对象.

复制代码

Vue.component('comp1', {
    template: "#comp1",
    data() {
        return {
            "types":[
                        {id:1, name:"手机类"},
                        {id:2, name:"日用品"},
                        {id:3, name:"空调类"},
                        {id:4, name:"电脑设备"},
                        {id:5, name:"家用电器"},
            ]
        }
    }
}            

复制代码

上面定义了一个组件, 组件定义了商城产品的类型

template id="comp1">
        <div>
            <button v-for="item in types" @click="clicktype(item)">{{item.name}}</button>
        </div>
</template>

定义一个组件模板,  循环遍历商品类型, 并定义了一个点击事件. clicktype(item)

复制代码

Vue.component('comp1', {
            template: "#comp1",
            data() {
                return {
                    "types":[
                        {id:1, name:"手机类"},
                        {id:2, name:"日用品"},
                        {id:3, name:"空调类"},
                        {id:4, name:"电脑设备"},
                        {id:5, name:"家用电器"},
                    ]
                }
            },
            methods:{
                clicktype(item) {
                    this.$emit('itemclick',item)
                    console.log("点击类型", item)
                }
            }
        })

复制代码

在点击事件中, 我们使用this.$emit('itemclick', item)定义了一个事件, 并将元素对象item传递给了事件.

那么父组件如何接受这个事件呢? 

父组件需要定义这个事件的监听. 通常我们都是监听点击事件click, 按键事件input等自带事件, 这里需要监听的是自定义事件

    <div id="app">
        <comp1 @itemclick="itemClick"></comp1>
    </div>

监听事件使用v-on:事件名称, 简写为@itemclick. 然后在父组件定义时间itemClick

复制代码

 var app = new Vue({
            el: "#app",
            data: {
                message: "hello"
            },
            methods:{
                itemClick(item) {
                    console.log("传递事件到父组件", item)
                }
            }
        });

复制代码

这样就可以接收到子组件传递过来的数据了.

总结一下:

1. 在模板中定义一个事件, 调用this.$emit('事件名称', 传递参数....)

2. 在模板调用的时候监听事件. @事件名称="方法名()"

3. 在父组件中定义方法来接收事件监听.

 

案例源码:

复制代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
     <!-- 2. 绑定事件 -->
        <comp1 @itemclick="itemClick"></comp1>
    </div>
    <template id="comp1">
        <div>
            <button v-for="item in types" @click="clicktype(item)">{{item.name}}</button>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component('comp1', {
            template: "#comp1",
            data() {
                return {
                    "types":[
                        {id:1, name:"手机类"},
                        {id:2, name:"日用品"},
                        {id:3, name:"空调类"},
                        {id:4, name:"电脑设备"},
                        {id:5, name:"家用电器"},
                    ]
                }
            },
            methods:{
                clicktype(item) {
            // 1. 注册事件
                    this.$emit('itemclick',item)
                    console.log("点击类型", item)
                }
            }
        })
        var app = new Vue({
            el: "#app",
            data: {
                message: "hello"
            },
            methods:{
          // 3.接收事件
                itemClick(item) {
                    console.log("传递事件到父组件", item)
                }
            }
        });
    </script>
</body>
</html>

复制代码

效果如下图


http://www.niftyadmin.cn/n/908822.html

相关文章

前端vue开发之二---双向绑定,父子组件访问

实际应用项目&#xff1a;http://github.crmeb.net/u/long 本文主要说两件事 1. 如何实现父子组件之间的双向绑定 2. 父组件如何访问子组件的data,method, 子组件如何访问父组件的data,method等 一. 如何实现父子组件之间的双向绑定 案例描述: 父子组件双向绑定 父组件有一…

[Log]ASP.NET之HttpModule拦截404异常

Httpmodule代码&#xff1a; public class Error404Module : IHttpModule{public void Init(HttpApplication context){context.Error new EventHandler(Context_Error);}protected void Context_Error(object sender, EventArgs e){HttpContext ctx HttpContext.Current;Htt…

supervisor守护进程配置

实际应用项目&#xff1a;http://github.crmeb.net/u/long 软硬件环境 centos7.6.1810 64bit cat /etc/redhat-release #查看系统版本 supervisor 3.4.0 python 2.7.5 supervisor简介 supervisor是一个用python语言编写的进程管理工具&#xff0c;它可以很方便的监听、启动…

Java compiler level does not match the version of the installed Java project facet.

问题原因&#xff1a; Facted Project 中的Java 版本设定与项目的Java编译器的compliance level设定不一致。 解决办法&#xff1a; 把两者设置成相同。 转载于:https://www.cnblogs.com/starxing/p/5751778.html

登录授权验证之OAuth2.0

实际应用项目&#xff1a;http://github.crmeb.net/u/long 本文将从几个方面了解和学习使用OAuth2.0。对不对就不管了&#xff0c;反正我也几乎不会用到。ps.有个项目用到了&#xff0c;所以才会有本文。 OAuth2.0介绍和功能微信开放平台和github的OAuth2.0接入应用自己写一个…

2010-2011 ACM-ICPC, NEERC, Moscow Subregional Contest Problem I. Interest Targeting 模拟题

Problem I. Interest Targeting题目连接&#xff1a; http://codeforces.com/gym/100714 Description A unique display advertisement system was developed at the department of advertising technologies, Yaagl Inc. The system displays advertisements that meet the in…

Linux 服务器必备的安全设置

这里给大家推荐一款免费迭代 二开便捷的商城项目&#xff1a;源码直通车>>> 好不容易买了服务器&#xff0c;如果因为自己的疏忽&#xff0c;被黑客黑掉的话&#xff0c;那真的是太糟糕了&#xff01; 下面告诉你一些简单的方法提高服务器的安全系数&#xff0c;我的…

面向对象重载

1.使用面向对象来求两个圆之间的面积2.函数重载函数重载需要的条件&#xff1a;函数名要相同&#xff0c;参数的个数或者参数的类型不同3.this关键字虽然写在类里面&#xff0c;但不是属于类的&#xff0c;而是属于该对象的一般来说在类里面 this关键字是可以省略的&#xff0c…