二、vue组件化开发(轻松入门vue)

轻松入门vue系列

  • 组件化思想:标准、分治、重用、组合
  • 组件 (Component) 是 Vue.js 最强大的功能之一
  • 组件可以扩展 HTML 元素,封装可重用的代码

五、组件化开发

1. 组件注册

官方强烈推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符)。这会帮助你避免和当前以及未来的 HTML 元素相冲突。

组件命名规范
  1. 当使用 短横线分隔命名定义一个组件时,你也必须在引用这个自定义元素时使用短横线分隔命名例如:
Vue.component('my-component-name', { /* ... */ })
<my-component-name>
  1. 当使用 首字母大写命名定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用(在组件模板内容中)直接在dom中依旧只能使用短横线分割的形式。
Vue.component('MyComponentName', { /* ... */ })
<my-component-name>或者<MyComponentName>
组件注册注意事项
  1. data必须是一个函数

data使用函数会形成一个闭包的环境,保证每个组件的数据是独立的。

Vue.component('button-counter',{
        //组件中需要的数据
       data: function () {
           return{
               count:0
           }
       },
        //组件模板内容
        template:`
            <div>
                <button @click='handel'>点击了{{count}}次</button>
                <button>确定</button>
            </div>
        `,
        methods:{
           handel:function () {
               this.count+=2;
           }
        }
    });
    ```
2. 组件模板内容必须是单个根节点的元素

```vue
<!--错误-->
<button @click='handel'>点击了{{count}}次</button>
<button>确定</button>
<!--正确-->
<div>
	<button @click='handel'>点击了{{count}}次</button>
	<button>确定</button>
</div>
  1. 组件模板内容可以是模板字符串(ES6语法需要浏览器支持)

当模板很长的时候使用字符串形式代码将会十分繁杂

//组件模板内容
template:"<div>\n" +
    "\t<button @click='handel'>点击了{{count}}次</button>\n" +
    "\t<button>确定</button>\n" +
    "</div>",

vue提供模板字符串形式,在模板外部加上反引号

//组件模板内容
template:`
    <div>
        <button @click='handel'>点击了{{count}}次</button>
        <button>确定</button>
    </div>
`,
全局组件注册

注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中

Vue.component('组件名称', {
	data:组件数据(必须是一个函数),
	template:组件模板内容
});

demo

<body>
    <div id="app">
        <button-counter></button-counter>
        <button-counter></button-counter>
    </div>
    <script>
        //组件注册
        Vue.component('button-counter',{
            //组件中需要的数据
           data: function () {
               return{
                   count:0
               }
           },
            //组件模板内容
            template:"<button @click='handel'>点击了{{count}}次</button>",
            methods:{
               handel:function () {
                   this.count+=2;
               }
            }
        });
        var vue = new Vue({
            el:"#app",
            data:{

            },
        })
    </script>
</body>
局部组件注册

只能在注册他的父组件中使用

//可以通过一个普通的 JavaScript 对象来定义组件:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
//在 components 选项中定义你想要使用的组件:
new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

demo

<div id="app1">
    <component-a></component-a>
</div>
<script>
    var ComponentA = {
        //组件中需要的数据
        data: function () {
            return{
                count:0
            }
        },
        //组件模板内容
        template:`
            <div>
                <button @click='handel'>点击了{{count}}次</button>
                <button>确定</button>
            </div>
        `,
        methods:{
            handel:function () {
                this.count+=2;
            }
        }
    };
    new Vue({
        el: '#app1',
        components: {
            'component-a': ComponentA,
        }
    })
</script>
2. Vue调试工具下载

vue-devtools是一款基于chrome游览器的插件,用于调试vue应用,这可以极大地提高我们的调试效率。

  1. 根据官网提示信息去github下载安装

在这里插入图片描述
2. chrome商店直接下载
在这里插入图片描述

方便的查看各组件之间的关系,能够直接清楚的看到组件中的数据

在这里插入图片描述

3. 组件间数据交互
父组件向子组件传值
  1. 组件内部通过props接收传递过来的值

props用于接收父组件传递过来的数据,是一个数组

Vue.component('blog-post', {
  // 在 JavaScript 中是 camelCase 的
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
  1. 父组件通过属性将值传递给子组件
<blog-post post-title="来自父组件的数据!"></blog-post>
<!--也可以是绑定的数据-->
<blog-post :post-title="post"></blog-post>

demo

<div id="app">
    <!--直接传值、注意不能用postTitle(Html大小写不敏感)-->
    <blog-post post-title="来自父组件的数据"></blog-post>
    <!--通过 v-bind 动态赋值-->
    <blog-post :post-title="postTitle"></blog-post>
</div>
<script>
    Vue.component('blog-post', {
        // 在 JavaScript 中是 camelCase 的
        props: ['postTitle'],
        data:function(){
          return{
              msg:"子组件本身的数据"
          }
        },
        template: '<h3>{{ postTitle +"----" + msg}}</h3>'
    });
    var vue =new Vue({
        el:"#app",
        data:{
            postTitle:"postTitle",
        },
    })
</script>
  1. props属性名规则

在props中使用驼峰形式,模板中需要使用短横线的形式

字符串式的模板中没有这个限制(在template模板中给子组件传值可以使用驼峰形式)

  1. props属性值类型

字符串String(略)

数值Number

<!-- 即便 `42` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:likes="42"></blog-post>

<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:likes="post.likes"></blog-post>

布尔值Boolean

<!-- 包含该 prop 没有值的情况在内,都意味着 `true`。-->
<blog-post is-published></blog-post>

<!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:is-published="false"></blog-post>

<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:is-published="post.isPublished"></blog-post>

数组Array

<!-- 即便数组是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>

<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>

对象Object

<!-- 即便对象是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post
  v-bind:author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
></blog-post>

<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:author="post.author"></blog-post>
props传递数据原则:单向数据流。

只允许父组件向子组件传递数据,不允许子组件直接操作props中的数据

子组件向父组件传值
  1. 子组件通过自定义事件向父组件传递信息
Vue.component('menu-text',{
        template:`
            <button @click="$emit('enlarge-text')">字体变大</button>
        `
    });
  1. 父组件监听子组件的事件
<menu-text @enlarge-text="handel"></menu-text>

demo

<div id="app">
    <div :style="{fontSize:fontSize+'px'}">字体</div>
    <menu-text @enlarge-text="handel"></menu-text>
</div>
<script>
    Vue.component('menu-text',{
        template:`
            <button @click="$emit('enlarge-text')">字体变大</button>
        `
    });

    var vue = new Vue({
        el:"#app",
        data:{
            fontSize:5,
        },
        methods:{
            handel:function () {
                this.fontSize+=10;
            }
        }
    })
</script>
  1. 子组件通过自定义事件向父组件传递信息
<button @click="$emit('enlarge-text',10)">字体变大</button>
  1. 父组件监听子组件的事件
<menu-text @enlarge-text="handel($event)"></menu-text>

demo

<div id="app">
    <div :style="{fontSize:fontSize+'px'}">字体</div>
    <menu-text @enlarge-text="handel($event)"></menu-text>
</div>
<script>
    Vue.component('menu-text',{
        template:`
            <button @click="$emit('enlarge-text',10)">字体变大</button>
        `
    });

    var vue = new Vue({
        el:"#app",
        data:{
            fontSize:5,
        },
        methods:{
            handel:function (val) {
                this.fontSize+=val;
            }
        }
    })
</script>
非父子组件之间传值
  1. 单独的时间中心管理组件间的通信
var hub = new Vue();// 提供事件中心
  1. 监听事件与销毁事件
// 监听事件(创建一个监听事件)
hub.$on('tom-event', (val) => {
	this.num += val;
});
//销毁事件
hub.$off('tom-event');
  1. 触发事件
// 触发兄弟组件的事件
hub.$emit('tom-event', 1);

demo

<div id="app">
    <div>父组件</div>
    <div>
        <button @click='handle'>销毁事件</button>
    </div>
    <test-tom></test-tom>
    <test-jerry></test-jerry>
</div>
<script type="text/javascript">
    /*
      兄弟组件之间数据传递
    */
    // 提供事件中心
    var hub = new Vue();

    Vue.component('test-tom', {
        data: function(){
            return {
                num: 0
            }
        },
        template: `
        <div>
          <div>TOM:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
        methods: {
            handle: function(){
                hub.$emit('jerry-event', 2);
            }
        },
        mounted: function() {
            // 监听事件
            hub.$on('tom-event', (val) => {
                this.num += val;
            });
        }
    });
    Vue.component('test-jerry', {
        data: function(){
            return {
                num: 0
            }
        },
        template: `
        <div>
          <div>JERRY:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
        methods: {
            handle: function(){
                // 触发兄弟组件的事件
                hub.$emit('tom-event', 1);
            }
        },
        mounted: function() {
            // 监听事件
            hub.$on('jerry-event', (val) => {
                this.num += val;
            });
        }
    });
    var vm = new Vue({
        el: '#app',
        data: {

        },
        methods: {
            handle: function(){
                hub.$off('tom-event');
                hub.$off('jerry-event');
            }
        }
    });
</script>
4. 组件插槽

父组件向子组件传递内容(模板的内容,区别去上面的数据交互)

父组件标签之间的内容会放置到子组件插槽中

基本用法

当组件渲染的时候,<slot></slot>将会被替换为“hello Vue”。插槽内可以包含任何模板代码,包括 HTML:

  1. 插槽位置
Vue.component('text-show',{
        template:`
            <div>
                <strong>莫逸风</strong>
                <slot></slot>
            </div>
        `
    });
  1. 插槽内容
<text-show>hello Vue</text-show>

demo

<div id="app">
    <text-show>
        <strong>HelloVue</strong>
    </text-show>
</div>
<script>

    Vue.component('text-show',{
        template:`
            <div>
                <strong>莫逸风</strong>
                <slot></slot>
            </div>
        `
    });

    var vue = new Vue({
        el:"#app",
        data:{

        },
    })
</script>
  1. 编译作用域

hello访问的是app实例中的数据,而不是text-show中的数据

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

<div id="app">
    <text-show>
        <strong>{{hello}}</strong>
    </text-show>
</div>
  1. 后备内容

在子组件中solt标签中添加默认内容

<slot>默认</slot>

插槽无内筒显示默认内容

<text-show></text-show>    <!--显示“默认”-->

插槽有内容覆盖默认内容

<text-show>莫逸风</text-show>    <!--显示“莫逸风”-->
具名插槽用法

自 2.6.0 起有所更新。已废弃的使用 slot attribute 的语法在这里

  1. 插槽定义

一个不带 nameslot 出口会带有隐含的名字“default”。

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
  1. 插槽内容

我们可以在一个 <template> 元素上使用 v-slot 指令,其参数对应插槽name

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

demo

<div id="app">
    <base-layout>
        <template v-slot:header>
            <h1>Here might be a page title</h1>
        </template>

        <p>A paragraph for the main content.</p>
        <p>And another one.</p>

        <template v-slot:footer>
            <p>Here's some contact info</p>
        </template>
    </base-layout>
</div>
<script>

    Vue.component('base-layout',{
        template:`
            <div class="container">
              <header>
                <slot name="header"></slot>
              </header>
              <main>
                <slot></slot>
              </main>
              <footer>
                <slot name="footer"></slot>
              </footer>
            </div>
        `
    })

    var vue =new Vue({
        el:"#app",
        data:{

        },
    })
</script>
作用域插槽

自 2.6.0 起有所更新。已废弃的使用 slot-scope attribute 的语法在这里

有时让插槽内容能够访问子组件中才有的数据是很有用的。

  1. 插槽定义

为了让 user 在父级的插槽内容中可用,我们可以将 user 作为 slot 元素的一个 attribute 绑定上去

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>
  1. 插槽内容

绑定在 <solt> 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字:

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

demo

<div id="app">
    <current-user :user="user">
        <template v-slot:default="slotProps">
            {{ slotProps.bindUser.firstName }}
        </template>
    </current-user>
    <current-user :user="user"></current-user>
</div>
<script>
    Vue.component('current-user',{
        props: ['user'],
        template:`
            <span>
              <slot v-bind:bindUser="user">
                {{ user.lastName }}
              </slot>
            </span>
        `
    })

    var vue = new Vue({
        el:"#app",
        data:{
            user:{
                firstName:"莫",
                lastName:"逸风",
            }
        }
    })
</script>
  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Vue3是一种流行的JavaScript框架,用于构建用户界面。Vue Router是Vue.js的官方路由器,用于实现单页面应用程序的导航功能。Vite是一个快速的Web开发构建工具,具有即时重载和快速的开发体验。Pinia是一个简单、快速、类型安全的状态管理库。 使用Vue3、Vue Router、Vite和Pinia进行组件开发实战入门非常简单。 首先,我们需要安装Vue3和相关的库。可以使用npm或yarn来安装它们。在项目的根目录中运行以下命令: ``` npm install vue@next vue-router@next @pinia/vue@next vite --save ``` 安装完成后,我们可以开始创建一个Vue应用程序。在项目的根目录中创建一个`src`文件夹,并在其中创建一个`main.js`文件。在`main.js`文件中,我们需要导入VueVue Router和Pinia,并创建一个Vue实例。代码示例如下: ```javascript // main.js import { createApp } from 'vue'; import { createRouter, createWebHistory } from 'vue-router'; import { createPinia } from 'pinia'; // 导入组件 import App from './App.vue'; // 创建路由 const router = createRouter({ history: createWebHistory(), routes: [ // 定义路由 { path: '/', component: Home } ] }); // 创建 Pinia 实例 const pinia = createPinia(); // 创建 Vue 实例 const app = createApp(App); // 使用路由和 Pinia app.use(router); app.use(pinia); // 挂载应用 app.mount('#app'); ``` 现在,我们可以创建一个简单的Vue组件。在`src`文件夹中创建一个名为`App.vue`的文件,并在其中定义一个组件。在组件中,我们可以使用Pinia来管理组件的状态,使用Vue Router来处理导航。 ```html <!-- App.vue --> <template> <div> <router-view></router-view> <button @click="increment">增加计数器</button> <p>{{ count }}</p> </div> </template> <script> import { defineComponent } from 'vue'; import { useCounter } from '../store'; export default defineComponent({ setup() { const counter = useCounter(); const increment = () => { counter.increment(); }; return { count: counter.count, increment }; } }); </script> ``` 在上述示例中,我们创建了一个Counter组件,其中包含一个用于增加计数器的按钮和一个显示计数器值的段落。我们使用Pinia的`useCounter`钩子来访问和修改计数器的状态。 最后,在项目的根目录中运行以下命令启动应用程序: ``` npm run dev ``` 以上就是使用Vue3、Vue Router、Vite和Pinia进行组件开发实战入门的一个简单示例。通过深入学习这些工具和框架,您将能够构建更复杂、功能丰富的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫逸风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值