03Vue的组件化开发

news/2024/7/19 16:06:12 标签: 过滤器, vue, html, js, python
htmledit_views">

Vue的组件化开发


组件注册

  1. 全局组件注册的语法
Vue.component(组件名称,{
    data: 组件数据,
    template: 组件模板内容
});

注意:
1.data必须是一个函数(目的是形成闭包环境,使数据独立)
2.组件模板的内容必须是单根元素
3.组件模板内容可以是模板字符串(ES6)
4.组件命名方式
其中,若使用驼峰的方式命名,则只能在字符串模板中使用,在普通的标签模板中还必须转换为短横线的方式(全部字母小写,并使用短横线相连)
    * 短横线方式
Vue.component("my-component",{});
    * 驼峰方式
Vue.component("MyComponent",{});
  1. 组件用法
html">1.可直接将名称作为标签,在html中使用
例:
<div id="app">
    <button-counter></button-counter>
</div>
2.组件可以充分使用,并且组件之间的数据相互隔离互不影响
<div id="app">
    <button-counter></button-counter>
    <button-counter></button-counter>
    <button-counter></button-counter>
</div>

实例:使用组件的方式,实现点击按钮触发数据自增的功能。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <button-counter></button-counter>
        <button-counter></button-counter>
        <button-counter></button-counter>
    </div>
    <script src="js/jquery-3.4.1.js"></script>
    <script src="js/html" title=vue>vue.js"></script>
    <script>
       Vue.component("button-counter",{
           data: function(){
                return {
                    num: 0
                }
           },
           template: "<button @click='handle'>点击了{{num}}次</button>",
           methods: {
                handle: function(){
                    this.num++;
                }
           }
       });
       var vm = new Vue({
           el: "#app",
           data: {
           }
      });
    </script>
</body>

</html>
  1. 局部组件注册

局部组件只能在注册的父容器中使用,在其他组件中无法使用。此处,与自定义指令和html" title=过滤器>过滤器类似。

var ComponentA = {};
var ComponentB = {};
var ComponentC = {};
new Vue({
   el: "#app",
   components: {
       'component-a':ComponentA,
       'component-b':ComponentB,
       'component-c':ComponentC
   }
});

实例:通过局部组件注册几个组件,并调用测试。

html"><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <hello-yorick></hello-yorick>
        <hello-tom></hello-tom>
    </div>
    <script src="js/jquery-3.4.1.js"></script>
    <script src="js/html" title=vue>vue.js"></script>
    <script>
        var helloYorick = {
            data: function(){
                return {
                    msg: "Hello yorick"
                };
            },
            template: "<div>{{msg}}</div>"
        };
        var helloTom = {
            data: function(){
                return {
                    msg: "Hello tom"
                };
            },
            template: "<div>{{msg}}</div>"
        };
        var vm = new Vue({
            el: "#app",
            data: {
            },
            components:{
                "hello-yorick": helloYorick,
                "hello-tom": helloTom
            }
        });
    </script>
</body>

</html>

组件间的数据交互

  1. 父组件向子组件传值
  • 组件内部通过props接收传递过来的数值
Vue.component("menu-item",{
   props:["title"],
   template: "<div>{{title}}</div>"
});

注意:
1.若在props中使用驼峰形式,则普通标签模板中需要使用短横线的形式传递。而在字符串形式的模板中没有此限制。
2.props是单向数据流。
  • 父组件通过属性将值传递给子组件,有以下三种传递方式
html">1.传递静态的值
<menu-item title="来自父组件的数据"></menu-item>
2.传递动态的值
<menu-item :title="ptitle"></menu-item>
3.两者结合使用
<menu-item :title="ptitle" content="父组件传递的静态content值"></menu-item>

实例:通过父组件向子组件传递数据,并显示数据内容。

html"><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
       <div>{{fmsg}}</div>
       <menu-item title="父组件传递的静态title值"></menu-item>
       <menu-item :title="ptitle"></menu-item>
       <menu-item :title="ptitle" content="父组件传递的静态content值"></menu-item>
    </div>
    <script src="js/jquery-3.4.1.js"></script>
    <script src="js/html" title=vue>vue.js"></script>
    <script>
        Vue.component("menu-item",{
            props: ["title","content"],
            data: function(){
                return {
                    smsg: "子组件内容"
                }
            },
            template: "<div>{{smsg + '---' + title + '----' + content}}</div>"
        });
        var vm = new Vue({
            el: "#app",
            data: {
                ptitle: "父组件传递的动态title值",
                fmsg: "父组件的内容"
            }
        });
    </script>
</body>

</html>
  • props传递不同类型数据
字符串 String
数值 Number(通过v-bind绑定的属性,未绑定的为String类型)
布尔值 Boolean(通过v-bind绑定的属性,未绑定的为String类型)
数组 Array
对象 Object

实例:父组件向子组件传递不同类型的数据,并显示。

html"><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
       <menu-item :pstr="pstr" :pnum="233" :pboo="true" :parr="parr" :pobj="pobj"></menu-item>
    </div>
    <script src="js/jquery-3.4.1.js"></script>
    <script src="js/html" title=vue>vue.js"></script>
    <script>
        Vue.component("menu-item",{
            props: ["pstr","pnum","pboo","parr","pobj"],
            template: `
                <div>
                    <div>{{pstr}}</div>
                    <div>{{typeof pnum + '---' + pnum}}</div>
                    <div>{{typeof pboo + '---' + pboo}}</div>
                    <ul>
                        <li :key='index' v-for='(item,index) in parr'>{{item}}</li>
                    </ul>
                    <div>
                        <span>{{pobj.uname}}</span>
                        <span>{{pobj.age}}</span>
                    </div>
                </div>
            `
        });
        var vm = new Vue({
            el: "#app",
            data: {
               pstr: "String",
               parr: ["apple","lemon","banana"],
               pobj: {
                   uname: "alice",
                   age: 13
               }
            }
        });
    </script>
</body>

</html>
  1. 子组件向父组件传值
  • 子组件通过自定义事件向父组件传递信息
html"><button v-on:click="$emit('enlarge-text')">
    扩大字体
</button>
  • 父组件需要监听子组件传递的事件
html"><menu-item v-on:enlarge-text="fontSize+=0.1"></menu-item>

实例:通过子组件向父组件传递信息,使得父组件的文本大小增加。

html"><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <div :style="{fontSize:fontSize+'px'}">{{fmsg}}</div>
        <menu-item v-on:enlarge-text="handle"></menu-item>
    </div>
    <script src="js/jquery-3.4.1.js"></script>
    <script src="js/html" title=vue>vue.js"></script>
    <script>
        Vue.component("menu-item",{
           template: `
                <button @click="$emit('enlarge-text')">点击按钮</button>
           `
        });
        var vm = new Vue({
            el: "#app",
            data: {
              fmsg: "父文本内容",
              fontSize: 10
            },
            methods: {
                handle: function(){
                    this.fontSize += 5;
                }
            }
        });
    </script>
</body>

</html>
  • 子组件向父组件传递信息时携带参数
html"><button v-on:click="$emit('enlarge-text',0.1)">
    扩大字体
</button>
  • 父组件获取子组件传递的参数
html"><menu-item v-on:enlarge-text="fontSize+=$event"></menu-item>

实例:改进上述实例代码,实现将增加的值由子组件传递过来。

html"><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <div :style="{fontSize:fontSize+'px'}">{{fmsg}}</div>
        <menu-item v-on:enlarge-text="handle($event)"></menu-item>
    </div>
    <script src="js/jquery-3.4.1.js"></script>
    <script src="js/html" title=vue>vue.js"></script>
    <script>
        Vue.component("menu-item",{
           template: `
                <button @click="$emit('enlarge-text',5)">点击按钮</button>
           `
        });
        var vm = new Vue({
            el: "#app",
            data: {
              fmsg: "父文本内容",
              fontSize: 10
            },
            methods: {
                handle: function(val){
                    this.fontSize += val;
                }
            }
        });
    </script>
</body>

</html>
  1. 兄弟组件之间的数据传递
  • 单独的事件中心负责管理组件间的通信
var hub = new Vue();
  • 监听事件与销毁事件
hub.$on("add-todo",addTodo);
hub.$off("add-todo");
  • 触发事件
hub.$emit("add-todo",id);

实例:通过兄弟组件之间的数据传递,实现1号控制2号的数据变化,2号控制1号的数据变化。

html"><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <test-tom></test-tom>
        <test-jerry></test-jerry>
        <div>
            <button @click="handle">销毁事件</button>
        </div>
    </div>
    <script src="js/jquery-3.4.1.js"></script>
    <script src="js/html" title=vue>vue.js"></script>
    <script>
        var hub = new Vue();
        Vue.component("test-tom",{
            data: function(){
                return {
                    num: 0
                }
            },
            template: `
                <div>
                    <div>TOM:{{num}}</div>
                    <button @click='handle'>点击</button>
                </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>
                    <button @click='handle'>点击</button>
                </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>
</body>

</html>

组件插槽

  1. 组件插槽的基本使用
  • 插槽位置
Vue.component("alert-box",{
    template: `
        <div>
            <strong>Error:</strong>
            <slot></slot>
        </div>
    `
});
  • 插槽内容
html"><alert-box>出现异常</alert-box>

实例:使用插槽可以获取父组件中标签内部的数据。若数据为空,则会显示slot标签内的默认数据。

html"><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <alert-box>出现异常</alert-box>
        <alert-box></alert-box>
    </div>
    <script src="js/jquery-3.4.1.js"></script>
    <script src="js/html" title=vue>vue.js"></script>
    <script>
        Vue.component("alert-box",{
            template: `
                <div>
                    <strong>Error:</strong>
                    <slot>默认内容</slot>
                </div>
            `
        });
        var vm = new Vue({
            el: "#app",
            data: { 
            }
        });
    </script>
</body>

</html>
  1. 具名插槽的用法
  • 具名插槽定义
Vue.component("container",{
    template: `
        <div>
            <header>
                <slot name='header'></slot>
            </header>
            <main>
                <slot></slot>
            </main>
            <footer>
                <slot name='footer'></slot>
            </footer>
        </div>
    `
});
  • 具名插槽的内容
html">1.单个标签添加slot属性
<container>
    <h1 slot="header">标题内容</h1>
    <p>主要内容1</p>
    <p>主要内容2</p>
    <p slot="footer">底部内容</p>
</container>
2.多个标签添加slot属性
 <container>
     <template slot="header">
         <h1>标题内容1</h1>
         <h1>标题内容2</h1>
     </template>
     <p>主要内容1</p>
     <p>主要内容2</p>
     <template slot="footer">
         <p>底部内容1</p>
         <p>底部内容2</p>
     </template>
</container>

实例:按照插槽给予的名字,实施对应数据的绑定

html"><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <container>
            <h1 slot="header">标题内容</h1>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <p slot="footer">底部内容</p>
        </container>


        <container>
            <template slot="header">
                <h1>标题内容1</h1>
                <h1>标题内容2</h1>
            </template>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <template slot="footer">
                <p>底部内容1</p>
                <p>底部内容2</p>
            </template>
        </container>
    </div>
    <script src="js/jquery-3.4.1.js"></script>
    <script src="js/html" title=vue>vue.js"></script>
    <script>
        Vue.component("container",{
            template: `
                <div>
                    <header>
                        <slot name='header'></slot>
                    </header>
                    <main>
                        <slot></slot>
                    </main>
                    <footer>
                        <slot name='footer'></slot>
                    </footer>
                </div>
            `
        });
        var vm = new Vue({
            el: "#app",
            data: { 
            }
        });
    </script>
</body>

</html>
  1. 作用域插槽
  • 作用域插槽的定义
html"><div>
    <li :key='item.id' v-for='item in list'>
        <slot :info='item'>
            {{item.name}}
        </slot>  
    </li>
</div>
  • 作用域插槽的内容
html"><container :list="list">
    <template slot-scope="slotProps">
        <strong v-if='slotProps.info.id==2' class="current">
            {{slotProps.info.name}}
        </strong>
        <span v-else>{{slotProps.info.name}}</span>
    </template>
</container>

实例:通过作用域插槽实现对子组件中某个数据内容进行样式的加工处理。

html"><!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<style type="text/css">
  .current {
    color: orange;
  }
</style>
<body>
  <div id="app">
    <container :list="list">
      <template slot-scope="slotProps">
        <strong v-if='slotProps.info.id==2' class="current">
          {{slotProps.info.name}}
        </strong>
        <span v-else>{{slotProps.info.name}}</span>
      </template>
    </container>
  </div>
  <script type="text/javascript" src="js/html" title=vue>vue.js"></script>
  <script type="text/javascript">
    /*
      作用域插槽
    */
    Vue.component("container",{
      props:["list"],
      template: `
        <div>
          <li :key='item.id' v-for='item in list'>
            <slot :info='item'>
              {{item.name}}
            </slot>  
          </li>
        </div>
      `
    });
    var vm = new Vue({
      el: '#app',
      data: {
        list: [{
          id: 1,
          name: 'apple'
        },{
          id: 2,
          name: 'orange'
        },{
          id: 3,
          name: 'banana'
        }]
      }
    });
  </script>
</body>
</html>

案例

购物车组件化开发案例

html"><!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style type="text/css">
    .container {
    }
    .container .cart {
      width: 300px;
      /*background-color: lightgreen;*/
      margin: auto;
    }
    .container .title {
      background-color: lightblue;
      height: 40px;
      line-height: 40px;
      text-align: center;
      /*color: #fff;*/  
    }
    .container .total {
      background-color: #FFCE46;
      height: 50px;
      line-height: 50px;
      text-align: right;
    }
    .container .total button {
      margin: 0 10px;
      background-color: #DC4C40;
      height: 35px;
      width: 80px;
      border: 0;
    }
    .container .total span {
      color: red;
      font-weight: bold;
    }
    .container .item {
      height: 55px;
      line-height: 55px;
      position: relative;
      border-top: 1px solid #ADD8E6;
    }
    .container .item img {
      width: 45px;
      height: 45px;
      margin: 5px;
    }
    .container .item .name {
      position: absolute;
      width: 90px;
      top: 0;left: 55px;
      font-size: 16px;
    }

    .container .item .change {
      width: 100px;
      position: absolute;
      top: 0;
      right: 50px;
    }
    .container .item .change a {
      font-size: 20px;
      width: 30px;
      text-decoration:none;
      background-color: lightgray;
      vertical-align: middle;
    }
    .container .item .change .num {
      width: 40px;
      height: 25px;
    }
    .container .item .del {
      position: absolute;
      top: 0;
      right: 0px;
      width: 40px;
      text-align: center;
      font-size: 40px;
      cursor: pointer;
      color: red;
    }
    .container .item .del:hover {
      background-color: orange;
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="container">
      <cart></cart>
    </div>
  </div>
  <script type="text/javascript" src="js/html" title=vue>vue.js"></script>
  <script type="text/javascript">
    
    var cartHeader = {
      props:["uname"],
      template: `
        <div>
          <div class="title">{{uname}}的商品</div>
        </div>
      `
    };
    var cartList = {
      props:["list"],
      template: `
        <div>
          <div class="item" :key="item.id" v-for="item in list">
            <img :src="item.img"/>
            <div class="name">{{item.name}}</div>
            <div class="change">
              <a href="" @click.prevent="subNum(item.id)">-</a>
              <input type="text" class="num" :value="item.num" @blur="changeNum(item.id,$event)" />
              <a href="" @click.prevent="addNum(item.id)">+</a>
            </div>
            <div class="del" @click="del(item.id)">×</div>
          </div>
        </div>
      `,
      methods: {
        changeNum: function(id,event){
          this.$emit("change-num",{
            id:id,
            type: "change",
            num:event.target.value
          });
        },
        subNum: function(id){
          this.$emit("change-num",{
            id:id,
            type: "sub"
          });
        },
        addNum: function(id){
          this.$emit("change-num",{
            id:id,
            type: "add"
          });
        },
        del: function(id){
          this.$emit("del",id);
        }
      }
    };
    var cartFooter = {
      props: ["list"],
      template: `
        <div class="total">
          <span>总价:{{total}}</span>
          <button>结算</button>
        </div>
      `,
      computed: {
        total: function(){
          var sum = 0;
          this.list.forEach(item=>{
            sum += item.price * item.num;
          });
          return sum;
        }
      }
    };
    Vue.component("cart",{
      data: function(){
        return {
          uname: "yorick",
          list: [{
            id: 1,
            name: 'TCL彩电',
            price: 1000,
            num: 1,
            img: 'img/a.jpg'
          },{
            id: 2,
            name: '机顶盒',
            price: 1000,
            num: 1,
            img: 'img/b.jpg'
          },{
            id: 3,
            name: '海尔冰箱',
            price: 1000,
            num: 1,
            img: 'img/c.jpg'
          },{
            id: 4,
            name: '小米手机',
            price: 1000,
            num: 1,
            img: 'img/d.jpg'
          },{
            id: 5,
            name: 'PPTV电视',
            price: 1000,
            num: 2,
            img: 'img/e.jpg'
          }]
        }
      },
      template: `
        <div class="cart">
          <cart-header :uname='uname'></cart-header>
          <cart-list :list='list' @del="del($event)" @change-num="changeNum($event)"></cart-list>
          <cart-footer :list='list'></cart-footer>
        </div>
      `,
      components: {
        "cart-header": cartHeader,
        "cart-list": cartList,
        "cart-footer": cartFooter
      },
      methods: {
        del: function(id){
          this.list = this.list.filter(item=>{
            return item.id != id;
          });
        },
        changeNum: function(val){
          if(val.type == "change"){
            this.list.some(item=>{
              if(item.id == val.id){
                item.num = val.num;
                return true;
              }
            });
          }else if(val.type == "sub"){
            this.list.some(item=>{
              if(item.id == val.id){
                item.num--;
                return true;
              }
            });
          }else if(val.type == "add"){
            this.list.some(item=>{
              if(item.id == val.id){
                item.num++;
                return true;
              }
            });
          }
        }
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {
        
      }
    });

  </script>
</body>
</html>

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

相关文章

04Vue的前后端交互

Vue的前后端交互 Promise用法 异步调用 触发异步调用的方式 定时任务Ajax事件函数 多次异步调用的依赖分析 多次异步调用由于不同接口相应时间的差异&#xff0c;导致返回结果的顺序不确定。若想得到确定顺序的异步调用结果&#xff0c;则需要进行嵌套调用。造成回调地狱。 Pr…

05Vue的前端路由

Vue的前端路由 一 路由基本概念 路由的本质就是对应关系。 路由可分为&#xff1a; 后端路由&#xff1a;URL请求地址与服务器资源之间的对应关系。 image-20210127111943936.png前端路由&#xff1a;用户事件与事件处理函数之间的对应关系。 image-20210127112121083.png二 手…

06Vue的前端工程化

Vue的前端工程化 一 模块化规范 1.1模块化规范举例 浏览器端JS模块化规范&#xff1a;AMD&#xff0c;CMD服务器端JS模块化规范&#xff1a;CommonJS大一统的模块化规范&#xff1a;ES6 每个js文件都是独立的模块导入模块成员使用import关键字暴露模块成员使用export关键字 1.…

SpringSecurity实现分布式应用的单点登录

技术栈&#xff1a;SpringBoot Mybatis SpringSecurity 程序地址&#xff1a;https://github.com/yaokuku123/spring-security 功能&#xff1a;实现分布式应用的单点登录。 一 分布式单点登录的架构 1.1 架构图 image-20210225133423571.png用户认证&#xff1a;这一环节主要…

SpringSecurity结合OAuth2实现第三方授权

SpringSecurity结合OAuth2实现第三方授权 一 OAuth2第三方登录架构 1.1 授权码模式架构图 image-20210226091245385.png流程 【A服务客户端】需要用到【B服务资源服务】中的资源 第一步&#xff1a;【A服务客户端】将用户自动导航到【B服务认证服务】&#xff0c;这一步用户需要…

ftp服务搭建与使用

一 ftp服务器搭建 安装vsftpd软件(用于文件的上传和下载) sudo apt-get install vsftpd 修改配置文件 image-20210309202150811.png重启服务 sudo service vsftpd restart 二 ftp客户端使用 2.1 实名用户登录 1) ftpIP(server) 2) 输入用户名(server) 3) 输入密码 4) 上传put 【…

nfs服务搭建与使用

一 服务器端 安装nfs服务 sudo apt install nfs-kernel-server 创建nfs共享目录(不能在/root目录下) mkdir /home/nfsuser/nfs_share 修改配置文件 sudo vim /etc/exports(在exports文件中直接添加下面一行)# /home/nfsuser/nfs_share 共享目录的绝对路径# * 所有ping同服务器的…

b站视频下载与字幕下载方式总结

b站视频下载与字幕下载方式总结 我们经常浏览b站观看视频&#xff0c;遇到喜欢的时候想下载相关视频。此时&#xff0c;应该如何下载视频又该如何获取视频对应的字幕呢。本篇文章将具体探讨其中的步骤。希望可以帮助到有需求的童鞋。 一. 视频下载 说明&#xff1a;下载视频有…