Vue -组件入门

组件简介


  1. 模块

    理解:向外提供特定功能的 js 程序,一般就是一个 js 文件

    为什么:js 文件很多很复杂

    作用:复用 js,简化 js 的编写,提高 js 运行效率

  2. 组件

    定义:用来实现局部功能的代码和资源的集合(html/css/js/image...)

    为什么:一个界面的功能很复杂

    作用:复用编码,简化项目编码,提高运行效率

  3. 模块化

    当应用中的 js 都以模块来编写的,那这个应用就是一个模块化的应用

  4. 组件化

    当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用

组件的使用

1、基础概念

Vue 中的 Component (组件) 是可复用、封装的 Vue 实例,是构建 Vue 应用的基本单元 ------ 它将页面 UI 拆分为独立、可复用的模块,每个组件包含自身的模板(HTML)、逻辑(JS)和样式(CSS),实现代码的模块化与复用。

2、核心特点

  1. 可复用性:一个组件可在应用的多个位置重复使用(如按钮组件、卡片组件),减少冗余代码;
  2. 封装性:组件内部的 HTML 结构、数据逻辑、样式是封闭的,对外仅暴露必要的接口(如 props 传参、emit 事件);
  3. 独立性:拥有自己的作用域(数据、方法仅在组件内生效),不同组件间互不干扰;
  4. 组合性:组件可嵌套使用(父组件包含子组件),形成复杂的页面结构。

3、注册方式1

javascript 复制代码
<script src="./js/vue.js"></script>
<script>
    //1. 创建组件构造器 (预设选项)
    const com = Vue.extend({
        template: "<h1>我是组件。</h1>"
    });
    //2.注册组件
    Vue.component(
        "com1",
        com
    );
    //3.创建 vue 实例后,组件就可以使用了。
    const vue = new Vue({
        el: "#box"
    });
</script>

4.4、注册方式2

html 复制代码
<div id="app">
  <hello></hello>
</div>
<script src="./js/vue.js"></script>
<script>
Vue.component(
	'hello', 
	{template:'<h1>同学,你好(2)</h1>'}
);
const vm = new Vue(
	{
		el:"#app"
	}
);
</script>

4.5、组件携带数据的情况

javascript 复制代码
<div id="app">
    <!-- 使用定义的组件 -->
    <temp3></temp3>
    <my-com></my-com>
</div>
<!-- 定义组件模板 -->
<script type="text/x-template" id="com3">
    <div><h1>你好, {{name}} 同学</h1></div>
</script>

<script type="text/x-template" id="MyCom">
    <div><h1>你好, [MyCom]</h1></div>
</script>
<script src="../js/vue.min.js"></script>
<script>
  // 注册组件
  Vue.component( 
     'temp3', {
  	 template:'#com3',
  	 data(){
  		return { name:'ANDY' }
  	 }
  });
  Vue.component( 
     'myCom', {
  	 template:'#MyCom'
  });
  // 创建根实例
  const vm = new Vue({
  	el:"#app"		
  });
</script>

总结

  • Vue中使用组件的三大步骤:

定义组件(创建组件)

注册组件

使用组件(写组件标签)

  • 如何定义一个组件?

使用Vue.extend(options)创建,其中options和new Vue(options)时传入的options几乎一样,但也有点区别:

el不要写,为什么?

最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器

data必须写成函数,为什么?

避免组件被复用时,数据存在引用关系

  • 如何注册组件?

局部注册:new Vue的时候传入components选项

全局注册:Vue.component('组件名',组件)

编写组件标签:

私有组件

1、基础概念

在 Vue2 中,私有组件指仅能在某个特定组件(或 Vue 实例)内部使用的组件,其作用域被限定在注册它的父组件内,无法在其他组件 / 实例中直接调用,是组件模块化和作用域隔离的重要实现方式。

2、定义方式

私有组件通过组件内的 components 选项注册,步骤如下:

  • 先定义子组件(如对象形式或单独文件);
  • 在父组件的 components 中声明该子组件(键为组件名,值为组件对象 / 引入的组件);
  • 在父组件模板中直接使用子组件标签。

3、核心特点

  • 作用域局限:仅注册它的父组件及其子组件(若有)可使用,外部组件无法访问;
  • 避免命名冲突:不同父组件可注册同名私有组件,互不影响;
  • 按需注册:无需全局挂载,减少全局作用域污染,优化性能(仅父组件加载时初始化)。

4、使用场景

适用于仅在特定父组件内使用、无需全局复用的子组件,例如:

  • 某个页面独有的功能模块(如详情页的 "评论项" 组件);
  • 父组件内部的辅助 UI 组件(如自定义按钮、表单项)。

5、示例代码

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        .pr {
            color: orange;
        }
    </style>
</head>
<body>
    <div id="app">
        <login></login>
        <register></register>
    </div>
</body>
<script src="./js/vue.js"></script>
<!-- 定义组件模板 -->
<script id="regTemp" type="text/x-template">
    <div><h1>这是组件{{2}}</h1></div>
    <h1 class="pr">这是组件{{1}}</h1>
</script>
<script>
    new Vue({
        el: "#app",
        components: {
            login: {
                template: `<h1 class="pr">这是组件{{1}}</h1>`
            },
            register: {
                template: '#regTemp'
            }
        }
    });
</script>

</html>

5.6、与全局组件的区别

组件中的data

1、基础概念

在 Vue 组件中,data 是组件内部响应式状态的核心容器,用于存储组件自身的动态数据,是模板渲染、逻辑交互的基础,也是 Vue 数据驱动视图 核心思想的直接体现。

2、核心作用

1. 存储组件私有动态状态

data 专门存放组件自身拥有、可修改的私有数据(区别于 props 接收的外部只读数据),涵盖:

  • 表单输入值(如输入框的 value);
  • 页面展示的动态数据(如列表数据、计数 count);
  • 控制 UI 状态的标识(如弹窗显隐 showModal、加载状态 loading)。
2. 支撑模板的响应式渲染

data 中的数据与模板(`)绑定后,数据的任何修改都会自动触发视图更新(Vue 的响应式系统),无需手动操作 DOM。

2、测试代码

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        .pr {
            color: orange;
        }
    </style>
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="app">
        <temp1></temp1>
    </div>
</body>
<script>
    Vue.component(
        'temp1',
        {
            template: '<h1>我是组件, data: {{info}}</h1>',
            data: function () {
                return { info: '这是数据' }
            }
        }
    );
    new Vue({ el: "#app" });
</script>

</html>

组件的切换

1、功能描述

Vue 中组件切换指根据业务条件(如状态、路由、用户操作)在页面中替换显示不同组件,核心有 条件渲染、动态组件 两类核心方式,另有路由切换适配页面级组件场景。

2、条件渲染

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./js/vue.js"></script>
</head>
<body>
    <div id="app2">
        <div @click="swap">切换组件</div>
        <login v-if="flag"></login>
        <register v-else="flag"></register>
    </div>
</body>
<script>
    Vue.component(
        'login',
        {
            template:'<h2>登录组件。</h2>'
        }
    );
    Vue.component(
        'register',
        {
            template:'<h2>注册组件</h2>'
        }
    );
    new Vue({
        el:"#app2",
        data:{ flag:false },
        methods:{
            swap(){
                this.flag = !this.flag;
            }
        }
    });
    </script>
</html>

3、动态组件

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./js/vue.js"></script>
</head>
<body>

    <div id="app2">
        <a href="#" @click.prevent="comName='login'">显示登录</a>
        <a href="#" @click.prevent="comName='register'">显示注册</a>
        <component :is="comName"></component>
    </div>
</body>

<script>
    Vue.component(
        'login',
        {
            template: '<h2>登录组件。</h2>'
        }
    );
    Vue.component(
        'register',
        {
            template: '<h2>注册组件。</h2>'
        }
    );
    new Vue({
        el: "#app2",
        data: { comName: 'login' },
    });
</script>

</html>

组件间传值

1、功能描述

Vue 组件间传值 (组件通信) 是实现组件协作的核心,核心遵循【单向数据流】原则

需根据组件层级关系(父子、子父、兄弟、跨级 / 任意组件)选择对应方案.

2、父传子数据

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./js/vue.js"></script>
</head>
<body>
    <div id="app">
        <child message="hello!"></child>
    </div>
</body>

<script>
    // 注册
    Vue.component('child', {
        // 声明 props
        props: ['message'],
        // 同样也可以在 vm 实例中像 "this.message" 这样使用
        template: '<span>{{ message }}</span>'
    })
    // 创建根实例
    new Vue({
        el: '#app'
    })
</script>
</html>

3、动态传递

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./js/vue.js"></script>
</head>
<body>
    <div id="app">
        <div>
          <input v-model="parentMsg">
          <br>
          <child v-bind:message="parentMsg"></child>
        </div>
    </div>
</body>
<script>
// 注册
Vue.component('child', {
  // 声明 props
  props: ['message'],
  // 同样也可以在 vm 实例中像 "this.message" 这样使用
  template: '<span>{{ message }}</span>'
})
// 创建根实例
new Vue({
  el: '#app',
  data: {
    parentMsg: '父组件内容'
  }
})
</script>
</html>

4、子传父数据

Vue.js 组件 - 自定义事件

父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!

我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件

另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="app">
        <div id="counter-event-example">
            <p>{{ total }}</p>
            <button-counter v-on:increment="incrementTotal"></button-counter>
            <button-counter v-on:increment="incrementTotal"></button-counter>
        </div>
    </div>
</body>
<script>
    // 定义一个计数器组件
    Vue.component('button-counter', {
        template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
        data: function () {
            return {
                counter: 0
            }
        },
        methods: {
            incrementHandler: function () {
                this.counter += 1
                // $emit(eventName) 触发事件
                // 子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
                // 使用 increment 指向父级的事件
                this.$emit('increment')
            }
        },
    })
    new Vue({
        el: '#counter-event-example',
        data: {
            total: 0
        },
        methods: {
            incrementTotal: function () {
                this.total += 1
            }
        }
    })
</script>

</html>

data 必须是一个函数

每个实例可以维护一份被返回对象的独立的拷贝,如果 data 是一个对象则会影响到其他实例

5、方式对比

章节案例

1、案例描述

添加水果案例

2、代码示例

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./js/vue.js"></script>
    <style>
        body {
            background: #F5F5F5;
        }
        ul {
            list-style: none;
            padding: 0px;
        }
        span {
            margin-left: 10px;
        }
        [type='text'] {
            width: 120px;
            height: 30px;
        }
        [type='button'] {
            width: 80px;
            height: 30px;
        }
    </style>
</head>

<body>
    <div id="app">
        <ipt-box @func1="addItem"></ipt-box>
        <ul>
            <li v-for="item in list" :key="item.id">
                <span>水果名称: {{item.fruitName}}</span>
                <span>价格: {{item.price}}</span>
            </li>
        </ul>
    </div>
    <!-- 定义组件 -->
    <template id="temp1">
        <div>
            <div>
                <label>水果名称</label>
                <input type="text" v-model="fruitName" />
            </div>
            <div>
                <label>水果价格</label>
                <input type="text" v-model="price" />
            </div>
            <div>
                <input type="button" value="添加数据" @click="confirm" />
            </div>
        </div>
    </template>
</body>
<script>
    var iptBox = {
        template: '#temp1',
        data() {
            return { list: [] };
        },
        methods: {
            confirm: function () {
                var f = {
                    id: this.id, 
                    fruitName: this.fruitName,
                    price: this.price
                };
                this.$emit('func1', f);
            }
        }
    };

    var vm = new Vue(
        {
            el: '#app',
            data: {
                list: [
                    { id: 'f1', fruitName: '苹果', price: 5.6 },
                    { id: 'f2', fruitName: '雪梨', price: 4.3 },
                    { id: 'f3', fruitName: '哈密瓜', price: 2.3 },
                    { id: 'f4', fruitName: '葡萄', price: 4.4 }
                ]
            },
            methods: {
                addItem: function (fruit) {
                    this.list.push(fruit);
                }
            },
            // 注册局部组件
            components: {
                'ipt-box': iptBox
            }
        }
    );
</script>

</html>
相关推荐
御形封灵2 小时前
基于原生table实现单元格合并、增删
开发语言·javascript·ecmascript
颜颜yan_2 小时前
DevUI + Vue 3 入门实战教程:从零构建AI对话应用
前端·vue.js·人工智能
Irene19913 小时前
Prettier 配置文件 .prettierrc.js 和 .prettierrc.json 的区别
javascript·json
计算机毕设VX:Fegn08954 小时前
计算机毕业设计|基于springboot + vue服装商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·课程设计
cc蒲公英4 小时前
javascript有哪些内置对象
java·前端·javascript
zhangwenwu的前端小站4 小时前
vue 对接 Dify 官方 SSE 流式响应
前端·javascript·vue.js
叫我詹躲躲5 小时前
Vue 3 组件开发最佳实践:可复用组件设计模式
vue.js
AY呀5 小时前
# 🌟 JavaScript原型与原型链终极指南:从Function到Object的完整闭环解析 ,深入理解JavaScript原型系统核心
前端·javascript·面试
氤氲息5 小时前
鸿蒙 ArkTs 的WebView如何与JS交互
javascript·交互·harmonyos