Vue2入门必知必会

Vue从入门到精通

Vue.js介绍

Vue.js官方文档

vue.js有哪些功能

  • 声明式渲染

    • Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统。 比如:使用vue.js的插值表达式放在Dom的任意地方, 差值表达式的值将被渲染在Dom中。

  • 条件与循环

    • dom中可以使用vue.js提供的v-if、v-for等标签,方便对数据进行判断、循环。

  • 双向数据绑定

    • Vue 提供v-model 指令,它可以轻松实现Dom元素和数据对象之间双向绑定,即修改Dom元素中的值自动修改绑定的数据对象,修改数据对象的值自动修改Dom元素中的值。

  • 处理用户输入

    • 为了让用户和你的应用进行交互,我们可以用 v-on 指令添加一个事件监听器,通过它调用在 Vue 实例中定义的 方法

  • 组件化应用构建

    • vue.js可以定义一个一个的组件,在vue页面中引用组件,这个功能非常适合构建大型应用。

Vue必知必会

MVVM模式

vue.js是一个MVVM的框架,MVVM拆分解释为:

  • Model:负责数据存储

  • View:负责页面展示

  • View Model:负责业务逻辑处理(比如Ajax请求等),对数据进行加工后交给视图展示

MVVM要解决的问题是将业务逻辑代码与视图代码进行完全分离,使各自的职责更加清晰,后期代码维护更 加简单,Vue中的MVVM :

  • VM(ViewModel)可以把view视图和Model模型解耦合,VM的要做的工作就是vue.js所承担的

Vue页面结构解读

插值表达式

  • 在上图中,我们使用 {{msg}}的方式读取到了定义在Vue实列中的msg属性的值

  • 这种{{xxx}}的表达式就名为插值表达式

Vue常用系统指令解读

v-text

  • v-text指令用于将数据填充到标签中,作用于插值表达式类似,但是没有闪动问题

  • 如果数据中有HTML标签会将html标签一并输出

  • 注意:此处为单向绑定,数据对象上的值改变,插值会发生变化;但是当插值发生变化并不会影响数据对象的值

v-html

  • 用法和v-text 相似 但是他可以将HTML片段填充到标签中

  • 可能有安全问题, 一般只在可信任内容上使用 v-html永不用在用户提交的内容上

  • 它与v-text区别在于v-text输出的是纯文本,浏览器不会对其再进行html解析,但v-html会将其当html标签解析后输出。

v-cloak

  • 防止页面加载时出现闪烁问题

    • 解释 :<div>{{msg}}</div> 会有插值闪烁的问题

    • 首先我们给其 v-cloak 属性

    • 然后在css中,绑定该元素,并设置为元素隐藏

    • 这样,当我们Vue中的数据还没渲染的时候,该div元素是隐藏状态,不可见

    • 当Vue数据渲染后,Vue会把该元素的v-cloak 属性去除掉,也就解脱了隐藏的css绑定

    • 此时该div元素正常显示

<style type="text/css">
  [v-cloak]{
    display: none;
  }
  </style>
<body>
    
  <div id="app">
    <div  v-cloak >{{msg}}</div>
  </div>
    
 <script src="../node_modules/vue/dist/vue.js"></script>
    
  <script>
        new Vue({
            el:"#app",
            data:{
                msg:"Hello Vue",
            }
        })
    </script>
</script>
</body>
</html>

v-pre

  • 显示原始信息跳过编译过程

  • 跳过这个元素和它的子元素的编译过程。

  • 一些静态的内容不需要编译加这个指令可以加快渲染

<span v-pre>{{ this will not be compiled }}</span>    
    <!--  显示的是{{ this will not be compiled }}  -->
    <span v-pre>{{msg}}</span>  
     <!--   即使data里面定义了msg这里仍然是显示的{{msg}}  -->
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'Hello Vue.js'
        }
    });
</script>

v-once

  • 执行一次性的插值【当数据改变时,插值处的内容不会继续更新】

  <!-- 即使data里面定义了msg 后期我们修改了 仍然显示的是第一次data里面存储的数据即 Hello Vue.js  -->
     <span v-once>{{ msg}}</span>    
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'Hello Vue.js'
        }
    });
</script>

v-model

  • v-model是一个指令,限制在 <input>、<select>、<textarea>、components中使用

  • 当数据发生变化的时候,视图也就发生变化

  • 当视图发生变化的时候,数据也会跟着同步变化

v-on

  • 用来绑定事件的

  • 形式如:v-on:click 缩写为 @click;

  • 如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数

    • <button v-on:click='handle1'>点击1</button>
  • 如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,并且事件对象的名称必须是$event

    •  <button v-on:click='handle2(123, 456, $event)'>点击2</button>

v-bind(对象绑定class、数组绑定class、绑定style)

  • v-bind 指令被用来响应地更新 HTML 属性

  • 形式如: v-bind:src="imageSrc" 缩写为 :src="imageSrc"

  • v-bind:class指令可以与普通的class特性共存

  • v-bind 通过对象绑定class

    • v-bind:class="{textColor:isColor, textSize:isSize}"

    • isColor,isSize 对应vue data中的数据 如果为true 则对应的类名 渲染到页面上

    • 此时,类名为:class="box textColor textSize"

    • 当 isColor 和 isSize 变化时,class列表将相应的更新

      • 比如isSize我们设置为false

      • 此时的class为 : class="box textColor"

<ul class="box" v-bind:class="{textColor:isColor, textSize:isSize}">
    <li>学习Vue</li>
    <li>学习Node</li>
    <li>学习HTML</li>
</ul>
  <div v-bind:style="{color:activeColor,fontSize:activeSize}">对象语法</div><sript>
var vm= new Vue({
    el:'.box',
    data:{
        isColor:true,
        isSize:true,
        activeColor:"red",
        activeSize:"25px",
    }
})
</sript>
<style>
    .box{
        border:1px dashed #f0f;
    }
    .textColor{
        color:#f00;
        background-color:#eef;
    }
    .textSize{
        font-size:30px;
        font-weight:bold;
    }
</style>
  • v-bind 通过数组绑定class

    • 此时,类名为:class="box textColor textSize"

<body>
    <ul class="box" :class="[classA, classB]">
        <li>学习Vue</li>
        <li>学习Node</li>
        <li>学习React</li>
    </ul>
   
    <script src="../node_modules/vue/dist/vue.js"></script><script>
        var vm= new Vue({
    el:'.box',
    data:{
        classA:'textColor',
        classB:'textSize'
    }
})
    </script>
    <style>
        .box{
            border:1px dashed #f0f;
        }
        .textColor{
            color:#f00;
            background-color:#eef;
        }
        .textSize{
            font-size:30px;
            font-weight:bold;
        }
    </style>
</body>
  • 绑定对象和绑定数组的区别

    • 绑定对象的时候,对象的属性,即要渲染的类名 ,对象的属性值对应的是 data 中的数据

    • 绑定数组的时候数组里面存的是data 中的数据

v-bind 绑定style

<!-- 通过Vue中定义的styleObject对象与其绑定    -->
<div v-bind:style="styleObject">绑定样式对象</div>'
<!-- CSS 属性名可以用驼峰式或短横线分隔,如果不是从Vue中拿值,手写,记得用单引号括起来:background:'red'    -->
 <div v-bind:style="{ color: activeColor, fontSize: fontSize,background:'red' }">内联样式</div>
<!--数组语法可以将多个样式对象应用到同一个元素 -->
 <div v-bind:style="[styleObj1, styleObj2]"></div>
<script>
    new Vue({
      el: '#app',
      data: {
        styleObject: {
          color: 'green',
          fontSize: '30px',
          background:'red'
        },
        activeColor: 'green',
        fontSize: "30px"
      },
      styleObj1: {
             color: 'red'
       },
       styleObj2: {
            fontSize: '30px'
       }
​
</script>

v-if

  • 顾名思义,条件判断。当得到结果为true时,所在的元素才会被渲染。

 <div v-if="type === 'A'">
       A
    </div>
  <!-- v-else-if紧跟在v-if或v-else-if之后   表示v-if条件不成立时执行-->
    <div v-else-if="type === 'B'">
       B
    </div>
    <div v-else-if="type === 'C'">
       C
    </div>
  <!-- v-else紧跟在v-if或v-else-if之后-->
    <div v-else>
       Not A/B/C
    </div><script>
    new Vue({
      el: '#app',
      data: {
        type: 'C'
      }
    })
</script>

v-show

  • v-show,当得到结果为true时,所在的元素才会被显示。

  • v-show本质就是标签display设置为none,控制隐藏

    • v-show只编译一次,后面其实就是控制css,

    • 而v-if不停的销毁和创建,故v-show性能更好一点。

  • v-if是动态的向DOM树内添加或者删除DOM元素

    • v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件

v-for

  • 用于循环的数组里面的值可以是对象,也可以是普通元素

  • 第一个参数 v:value 即值

  • 第二个参数 k:key 即属

  • 第三个参数 i: index 即下标

遍历数组

<ul id="example-1">
   <!-- 循环结构-遍历数组  
    item 是我们自己定义的一个名字  代表数组里面的每一项  
    items对应的是 data中的数组-->
  <li v-for="item in items">
    {{ item.message }}
  </li></ul>
<script>
 new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})
</script>

遍历对象

  • 不推荐同时使用 v-ifv-for

    • v-ifv-for 一起使用时,v-for 具有比 v-if 更高的优先级。

 <div v-if='v==13' v-for='(v,k,i) in obj'>
     {{v + '---' + k + '---' + i}}
 </div>
<script>
 new Vue({
  el: '#example-1',
  data: {
    obj: {
        uname: 'zhangsan',
        age: 13,
        gender: 'female'
    }
  }
})
</script>

key的作用

  • key来给每个节点做一个唯一标识

  • key的作用主要是为了高效的更新虚拟DOM

<ul>
  <li v-for="item in items" :key="item.id">...</li>
</ul>

Vue常用特性

表单基操

  • 获取单选框中的值

  • 两个单选框需要同时通过v-model 双向绑定 一个值

  • 每一个单选框必须要有value属性 且value 值不能一样

  • 当某一个单选框选中的时候 v-model 会将当前的 value值 改变 data 中的 数据

<body>
    <div id="app">
        <input type="radio" id="male" value="1" v-model='gender'>
        <label for="male"></label><input type="radio" id="female" value="2" v-model='gender'>
        <label for="female"></label>
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        var vm = new Vue({
            el: '#app',
            data: {
                // 默认会让当前的 value 值为 2 的单选框选中
                gender: 2
            }
        })
    </script>
</body>
  • 获取复选框中的值

  • 复选框需要同时通过v-model 双向绑定 一个值

  • 每一个复选框必须要有value属性 且value 值不能一样

  • 当某一个单选框选中的时候 v-model 会将当前的 value值 改变 data 中的 数据

  • 复选框 checkbox 这种的组合时 data 中的 hobby 我们要定义成数组 否则无法实现多选

<body>
    <div id="app">
        <span>爱好:</span>
        <input type="checkbox" id="ball" value="1" v-model='hobby'>
        <label for="ball">篮球</label>
        <input type="checkbox" id="sing" value="2" v-model='hobby'>
        <label for="sing">唱歌</label>
        <input type="checkbox" id="code" value="3" v-model='hobby'>
        <label for="code">写代码</label>
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        var vm = new Vue({
            el: '#app',
            data: {
                hobby: ['2', '3']
            }
        })
    </script>
</body>
  • 获取下拉框和文本框中的值

  • 需要给select 通过v-model 双向绑定 一个值

  • 每一个option 必须要有value属性 且value 值不能一样

  • 当某一个option选中的时候 v-model 会将当前的 value值 改变 data 中的 数据

<body>
    <div id="app">
        <span>职业:</span>
         <!-- multiple  多选 -->
        <select v-model='occupation' multiple>
            <option value="0">请选择职业...</option>
            <option value="1">运维工程师</option>
            <option value="2">开发工程师</option>
            <option value="3">测试工程师</option>
        </select>
        <br />
        <!-- textarea 是一个双标签,不需要绑定value属性  -->
        <textarea v-model='desc'></textarea>
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        var vm = new Vue({
            el: '#app',
            data: {
                // 默认会让当前的 value 值为 1 和 2 的下拉框选中
                occupation: ["1","2"],
                desc: '我是文本内容'
            }
        })
    </script>
</body>

表单修饰符

  • .number 转换为数值

  • .trim 自动过滤用户输入的首尾空白字符

  • .lazy 将input事件切换成change事件

<body>
    <div id="app">
        <!-- 自动将用户的输入值转为数值类型 -->
        <input v-model.number="age" type="number">
        <!--自动过滤用户输入的首尾空白字符   -->
        <input v-model.trim="msg">
        <!-- 在“change”时而非“input”时更新,在失去焦点 或者 按下回车键时才更新 -->
        <input v-model.lazy="msg">
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        var vm = new Vue({
            el: '#app',
            data: {
                age: 15,
                msg: "ninjaTest"
            }
        })
    </script>
</body>

计算属性computed

  • 多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化

  • 比如买书,我们的总价就是一个计算属性,他的值会根据书本的数量的变化而变化

  • 计算属性与方法的区别:计算属性是基于依赖进行缓存的,而方法不缓存

  • 也就是说,只要我监听的数据没有发生变化,则我计算属性就只会计算一次,而不是多次计算

    • 下面我们调用两次计算属性,发现控制台只打印了一次

<body>
    <div id="app">
        <!-- 某些结果是基于之前数据实时计算出来的,我们可以利用计算属性。来完成 -->
        <ul>
            <li>西游记; 价格:{{xyjPrice}},数量:<input type="number" v-model="xyjNum"> </li>
            <li>水浒传; 价格:{{shzPrice}},数量:<input type="number" v-model="shzNum"> </li>
            <li>总价:{{totalPrice}}</li>
            <li>再三确认总价为:{{totalPrice}}</li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script><script>
        //watch可以让我们监控一个值的变化。从而做出相应的反应。
        new Vue({
            el: "#app",
            data: {
                xyjPrice: 10.98,
                shzPrice: 11.00,
                xyjNum: 1,
                shzNum: 1
            },
            computed: {
                totalPrice() {
                    console.log("计算属性在进行计算");
                    return this.xyjPrice * this.xyjNum + this.shzPrice * this.shzNum
                }
            }
        })
    </script>
</body>

监听器watch

  • 使用watch来响应数据的变化

  • 一般用于异步或者开销较大的操作

  • watch 中的属性 一定是data 中 已经存在的数据

  • 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听

<body>
    <div id="app">
        <div>
            <span>名:</span>
            <span>
                <input type="text" v-model='firstName'>
            </span>
        </div>
        <div>
            <span>姓:</span>
            <span>
                <input type="text" v-model='lastName'>
            </span>
        </div>
        <div>{{fullName}}</div>
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        var vm = new Vue({
            el: '#app',
            data: {
                firstName: 'chen',
                lastName: 'shimei',
                fullName: ''
            },
            watch: {
                firstName(val) {
                    this.fullName = val + ' ' + this.lastName;
                },
                lastName(val) {
                    this.fullName = this.firstName + ' ' + val;
                }
            }
        })
    </script>
</body>

过滤器

  • Vue.js允许自定义过滤器,可被用于一些常见的文本格式化。

  • 过滤器可以用在两个地方:双花括号插值和v-bind表达式。

  • 过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示

  • 支持级联操作

  • 过滤器不改变真正的data,而只是改变渲染的结果,并返回过滤后的版本

  • 全局注册时是filter,没有s的。而局部过滤器是filters,是有s的

<body>
    <div id="app">
        <ul>
            <li v-for="user in userList">
                {{user.id}} ==> {{user.name}} ==> {{user.gender == 1?"男":"女"}} ==>
                <!-- 使用过滤器 -->
                {{user.gender | genderFilter}} ==> {{user.gender | gFilter}}
            </li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script><script>
        //全局过滤器
        Vue.filter("gFilter", function (val) {
            if (val == 1) {
                return "男~~~";
            } else {
                return "女~~~";
            }
        })
​
        let vm = new Vue({
            el: "#app",
            data: {
                userList: [
                    { id: 1, name: 'jacky', gender: 1 },
                    { id: 2, name: 'peter', gender: 0 }
                ]
            },
            filters: {
                // filters 定义局部过滤器,只可以在当前vue实例中使用
                genderFilter(val) {
                    if (val == 1) {
                        return "";
                    } else {
                        return "";
                    }
                }
            }
        })
    </script>
</body>

过滤器传参数问题

  • filterA被定义为全局过滤器,一共接收三个参数

  • 当我们在调用该过滤器时

    • 默认第一个参数就是前面的message的值,为8

    • 然后后面的参数一次匹配

<body>
    <div id="app">
        {{ message | filterA('arg1', 'arg2') }}
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        Vue.filter('filterA', function (message, arg1, arg2) {
            if (message < 10) {
                return message + arg1;
            } else {
                return message + arg2;
            }
        });
​
        var vm = new Vue({
            el: '#app',
            data: {
                message: 8
            }
        })
    </script>
</body>

生命周期

  • Vue实例从创建 到销毁的过程 ,这些过程中会伴随着一些函数的自调用。我们称这些函数为钩子函数

<body>
    <div id="app">
        <span id="num">{{num}}</span>
        <button @click="num++">赞!</button>
        <h2>{{name}},有{{num}}个人为你点赞</h2>
    </div><script src="../node_modules/vue/dist/vue.js"></script>
    
    <script>
        let app = new Vue({
            el: "#app",
            data: {
                name: "张三",
                num: 100
            },
            methods: {
                show() {
                    return this.name;
                },
                add() {
                    this.num++;
                }
            },
            beforeCreate() {
                console.log("=========beforeCreate=============");
                console.log("数据模型未加载:" + this.name, this.num);
                console.log("方法未加载:" + this.show());
                console.log("html模板未加载:" + document.getElementById("num"));
            },
            created: function () {
                console.log("=========created=============");
                console.log("数据模型已加载:" + this.name, this.num);
                console.log("方法已加载:" + this.show());
                console.log("html模板已加载:" + document.getElementById("num"));
                console.log("html模板未渲染:" + document.getElementById("num").innerText);
            },
            beforeMount() {
                console.log("=========beforeMount=============");
                console.log("html模板未渲染:" + document.getElementById("num").innerText);
            },
            mounted() {
                console.log("=========mounted=============");
                console.log("html模板已渲染:" + document.getElementById("num").innerText);
            },
            beforeUpdate() {
                console.log("=========beforeUpdate=============");
                console.log("数据模型已更新:" + this.num);
                console.log("html模板未更新:" + document.getElementById("num").innerText);
            },
            updated() {
                console.log("=========updated=============");
                console.log("数据模型已更新:" + this.num);
                console.log("html模板已更新:" + document.getElementById("num").innerText);
            }
        });
    </script>
</body>
钩子函数解释
beforeCreate 在实例初始化之后,数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化 什么都做不了
created 在实例创建完成后被立即调用此时data 和 methods已经可以使用 但是页面还没有渲染出来
beforeMount 在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已
mounted el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。 数据已经真实渲染到页面上 在这个钩子函数里面我们可以使用一些第三方的插件
beforeUpdate 数据更新时调用,发生在虚拟DOM打补丁之前。 页面上数据还是旧的
updated 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 页面上数据已经替换成最新的
beforeDestroy 实例销毁之前调用
destroyed 实例销毁后调用

数组Pro

数组变异方法

  • 在 Vue 中,直接修改对象属性的值无法触发响应式。当你直接修改了对象属性的值,你会发现,只有数据改了,但是页面内容并没有改变

  • 变异数组方法即保持数组方法原有功能不变的前提下对其进行功能拓展

函数解释
push() 往数组最后面添加一个元素,成功返回当前数组的长度
pop() 删除数组的最后一个元素,成功返回删除元素的值
shift() 删除数组的第一个元素,成功返回删除元素的值
unshift() 往数组最前面添加一个元素,成功返回当前数组的长度
splice() 有三个参数,第一个是想要删除的元素的下标(必选),第二个是想要删除的个数(必选),第三个是删除 后想要在原位置替换的值
sort() sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组
reverse() reverse() 将数组倒序,成功返回倒序后的数组

替换数组

  • 不会改变原始数组,但总是返回一个新数组

函数解释
filter() filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
concat() concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组
slice() slice() 方法可从已有的数组中返回选定的元素。该方法并不会修改数组,而是返回一个子数组

动态数组响应式数据

  • Vue.set(a,b,c) 让 触发视图重新更新一遍,数据动态起来

  • a是要更改的数据 、 b是数据的第几项、 c是更改后的数据

组件Component

  • 组件参数的data值必须是函数同时这个函数要求返回一个对象

  • 组件模板必须是单个根元素

  • 组件模板的内容可以是模板字符串

  • 组件可以重复使用多次 但组件中data函数返回的是一个对象,所以每个组件中的数据是私有的

  • 如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件

    • 但是在普通的标签模板中,必须使用短横线的方式使用组件

组件全局注册

  • Vue.component('组件名称', { }) 第1个参数是标签名称,第2个参数是一个选项对象

  • 全局组件注册后,任何vue实例都可以用

  • 以下为最简版组件示范代码

<div id="example">
  <!-- 2、 组件使用 组件名称 是以HTML标签的形式使用  -->  
  <my-component></my-component>
</div>
<script>
    //   注册组件 
    // 1、 my-component 就是组件中自定义的标签名
    Vue.component('my-component', {
       data: function(){
        return {
          msg: 'Hello World'
        }
      },
      template: '<div> {{msg}} Vue Component! </div>'
    })
​
    // 创建根实例
    new Vue({
      el: '#example'
    })
</script>

组件局部注册

 <div id="app">
      <my-component></my-component>
  </div>
​
​
<script>
    // 定义组件的模板
    var Child = {
      template: '<div> Hello World Vue Component! </div>'
    }
    new Vue({
      //...局部注册组件  
      components: {
        // <my-component> 将只在父模板可用  一定要在实例上注册了才能在html文件中使用
        'my-component': Child
      }
    })
 </script>

Vue组件之间传值

父组件向子组件传值

  • 父组件发送的形式是以属性的形式绑定值到子组件身上。

  • 然后子组件用属性props接收

  • 在props中使用驼峰形式,模板中需要使用短横线的形式字符串形式的模板中没有这个限制

<body>
    <div id="app">
        <div>{{pmsg}}</div>
        <!--1、menu-item  在 APP中嵌套着 故 menu-item为子组件 -->
        <!-- 给子组件传入一个静态的值 -->
        <menu-item title='来自父组件的静态值1' content='来自父组件的静态值2'></menu-item>
        <!-- 2、需要动态的数据的时候 需要属性绑定的形式设置 此时ptitle来自父组件data 中的数据 . 
            传的值可以是数字、对象、数组等等 -->
        <menu-item :title='pmsg' :content='ptitle'></menu-item></div><script src="../node_modules/vue/dist/vue.js"></script><script>
        Vue.component('menu-item', {
            // 3、子组件用属性props接收父组件传递过来的数据  
            props: ['title', 'content'],
            data: function () {
                return {
                    msg: '子组件本身的数据'
                }
            },
            template: '<div> {{msg + "----" + title + "-----" + content}} </div>'
        });
        var vm = new Vue({
            el: '#app',
            data: {
                pmsg: '父组件中内容-1',
                ptitle: '父组件中内容-2'
            }
        });
    </script>
</body>

子组件向父组件传值

  • 子组件用$emit()触发事件

  • $emit() 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据

  • 父组件用v-on 监听子组件的事件

<body>
    <div id="app">
        <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
        <!-- 2 父组件用v-on 监听子组件的事件
           这里 enlarge-text  是从 $emit 中的第一个参数对应   handle 为对应的事件处理函数  
       -->
        <menu-item :parr='parr' @enlarge-text='handle($event)'></menu-item>
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        Vue.component('menu-item', {
            props: ['parr'],
            template: `
        <div>
          <ul>
            <li :key='index' v-for='(item,index) in parr'>{{item}}</li>
          </ul>
          <!--  1、子组件用$emit()触发事件 -->
          <!-- 第一个参数为 自定义的事件名称   第二个参数为需要传递的数据  -->
          <button @click='$emit("enlarge-text", 5)'>扩大父组件中字体大小</button>
          <button @click='$emit("enlarge-text", 10)'>扩大父组件中字体大小</button>
        </div>
      `
        });
        var vm = new Vue({
            el: '#app',
            data: {
                pmsg: '父组件中内容',
                parr: ['apple', 'orange', 'banana'],
                fontSize: 10
            },
            methods: {
                handle(val) {
                    // 扩大字体大小
                    this.fontSize += val;
                }
            }
        });
    </script>
</body>

兄弟组件之间传值

  • 兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据

    • 提供事件中心 var hub = new Vue()

  • 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)

  • 接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名

  • 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据

<body>
    <div id="app">
        <div>父组件</div>
        <div>
            <button @click='handle'>销毁事件</button>
        </div>
        <test-tom></test-tom>
        <test-jerry></test-jerry>
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        //1、 提供事件中心
        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() {
                    //2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)   触发兄弟组件的事件
                    hub.$emit('jerry-event', 2);
                }
            },
            mounted() {
                // 5、接收数据方,通过mounted(){} 钩子中  触发hub.$on(方法名
                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 () {
                    //4、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)   触发兄弟组件的事件
                    hub.$emit('tom-event', 1);
                }
            },
            mounted: function () {
                // 3、接收数据方,通过mounted(){} 钩子中  触发hub.$on()方法名
                hub.$on('jerry-event', (val) => {
                    this.num += val;
                });
            }
        });
        var vm = new Vue({
            el: '#app',
            data: {
​
            },
            methods: {
                handle: function () {
                    //6、销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据  
                    hub.$off('tom-event');
                    hub.$off('jerry-event');
                }
            }
        });
    </script>
</body>

组件插槽

  • 组件的最大特性就是复用性,而用好插槽能大大提高组件的可复用能力

匿名插槽

<body>
    <div id="app">
        <!-- 这里的所有组件标签中嵌套的内容会替换掉slot  如果不传值 则使用 slot 中的默认值  -->
        <alert-box>有bug发生</alert-box>
        <alert-box>有一个警告</alert-box>
        <alert-box></alert-box>
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        Vue.component('alert-box', {
            template: `
        <div>
          <strong>ERROR:</strong>
          <!-- 当组件渲染的时候,这个 <slot> 元素将会被替换为“组件标签中嵌套的内容” -->
          <!-- 插槽内可以包含任何模板代码,包括 HTML -->
          <slot>默认内容</slot>
        </div>
      `
        });
        var vm = new Vue({
            el: '#app',
            data: {
​
            }
        });
    </script>
</body>

具名插槽

  • 具有名字的插槽

  • 使用 <slot> 中的 "name" 属性绑定元素

<body>
    <div id="app">
        <base-layout>
            <!-- 2、 通过slot属性来指定, 这个slot的值必须和下面slot组件得name值对应上
                 如果没有匹配到 则放到匿名的插槽中   -->
            <p slot='header'>标题信息</p>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <p slot='footer'>底部信息</p>
        </base-layout>
        
        <hr /><base-layout>
            <!-- 注意点:该template标签最终不会渲染到页面上 template用于管理多个标签使其拥有相同的slot     -->
            <template slot='header'>
                <p>标题信息1</p>
                <p>标题信息2</p>
            </template>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <template slot='footer'>
                <p>底部信息1</p>
                <p>底部信息2</p>
            </template>
        </base-layout>
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        Vue.component('base-layout', {
            template: `
        <div>
          <header>
            <!--    1、 使用 <slot> 中的 "name" 属性绑定元素 指定当前插槽的名字 -->
            <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>

作用于插槽

  • 父组件对子组件加工处理

  • 既可以复用子组件的slot,又可以使slot内容不一致

<body>
    <div id="app">
        <fruit-list :list='list'>
            <!-- 2、 父组件中使用了<template>元素,而且包含scope="slotProps",
                 slotProps在这里只是临时变量   
             -->
            <template slot-scope='slotProps'>
                <strong v-if='slotProps.info.id==3'>
                    {{slotProps.info.name}}
                </strong>
                <span v-else>{{slotProps.info.name}}</span>
            </template>
        </fruit-list>
    </div><script src="../node_modules/vue/dist/vue.js"></script><script>
        Vue.component('fruit-list', {
            props: ['list'],
            template: `
        <div>
          <li :key='item.id' v-for='item in list'>
            <!--  3、 在子组件模板中,<slot>元素上有一个类似props传递数据给组件的写法msg="xxx",-->
            <!--   插槽可以提供一个默认内容,如果如果父组件没有为这个插槽提供了内容,会显示默认的内容。-->
            <!--如果父组件为这个插槽提供了内容,则默认的内容会被替换掉-->
            <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>

.

posted @ 2021-02-23 00:54  鞋破露脚尖儿  阅读(240)  评论(0编辑  收藏  举报