《Vue2.5开发去哪儿网App 从零基础入门到实战项目》note - Vue基础知识

164 阅读3分钟

Vue基础知识

2_2HelloWorld

<!DOCTYPE html>

<html>

  <head>

    <meta charset="UTF-8" />

    <title>Hello World</title>

    <script src="vue.js"></script>

  </head>

  <body>

    <div id="app">{{content}}</div>

    <script>

      /*             var dom=document.getElementById('app');

            dom.innerHTML='hello world'; */

      /*//用vue.js来写上面的dom

             var app=new Vue({//创建了vue的实例

                el:'#app',

                data:{

                content:'hello world'

            }}); */



    //vue.js实现两秒后修改文字

      var app = new Vue({

        el: "#app",

        data: {

          content: "hello world",

        },

      });

      setTimeout(function () {

        app.$data.content = "bye world";

      }, 2000);

    </script>

  </body>

</html>

<!-- <!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title></title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root"></div>



    <script>

      var vm = new Vue({

        el: '#root'

      });

    </script>

  </body>

</html> -->

2_3TodoList

<!DOCTYPE html>

<html>

  <head>

    <meta charset="UTF-8" />

    <title>TodoList</title>

    <script src="vue.js"></script>

  </head>

  <body>

    <div id="app">

        <input type="text" v-model="inputValue"><!-- 双向数据绑定 -->

        <button v-on:click="handleBtnClick">提交</button>

        <ul>

            <li v-for="item in list">{{item}}</li>

        </ul>

    </div>



    <script>

        //M层

        var app=new Vue({

            el:'#app',

            data:{

                list:[],

                inputValue:''//双向数据绑定

            },

            methods:{

                handleBtnClick:function(){

                    this.list.push(this.inputValue)

                    this.inputValue=''

                }

            }

        })

    </script>

  </body>

</html>

<!-- 2-3开发TodoList(v-model、v-for、v-on) -->

<!-- MVVM设计模式--触发点击事件时,不是改变DOM,而是去改变数据,数据变了,页面也跟着发生了变化。 Vue涉及数据层,不再涉及DOM的操作。当我们把数据进行变更的时候,Vue之中它的底层会自动根据数据的不同重新去渲染页面。Vue可以减少代码量。jquery大部分在操作DOM,-->

2_4MVVM

<!DOCTYPE html>

<html>

  <head>

    <meta charset="UTF-8" />

    <title>TodoList Jquery</title>

    <script src="jquery-3.5.1.js"></script>

  </head>

  <body>

      <!-- V层 -->

    <div>

        <input id="input" type="text">

        <button id="btn">提交</button>

        <ul id="list"></ul>

    </div>



    <script>

        function Page(){

            

        }



        $.extend(Page.prototype,{

            init:function(){

                this.bindEvents()

            },

            bindEvents:function(){

                var btn=$('#btn');

                btn.on('click',$.proxy(this.handleBtnClick,this))

            },

            handleBtnClick:function(){

                var inputElem=$("#input");

                var inputValue=inputElem.val();

                var ulElem=$("#list");

                ulElem.append('<li>'+inputValue+'</li>');

                inputElem.val('');

            }

        })



        var page=new Page();

        page.init();

    </script>

  </body>

</html>



<!-- 2-4MVVM模式 -->

<!-- MVP模式(Jquery):面向DOM -->

<!--View⇌Presenter⇌Model 

    M(Modle)-模型层(调用Ajax获取数据,这里省略掉了)

    V(View)-视图

    P(Presenter)-控制器(核心中转站):①用Ajax获取数据;②通过DOM操作来改变视图, 大量代码写在控制器,很大部分代码(70%-80%)在做DOM操作-->





<!-- MVVM模式 (Vue):面向数据-->

<!-- DOM的操作极大简化,代码量显著减少(在大型项目中至少30%) -->

<!-- Model←View←ViewModel←Model -->

<!-- View:DOM(编码的重点1)

    ViewModel(DOM Listener,Data Bindings):Vue

    Model:Plain JavaScript Objects(编码的重点2) -->



<!-- M层-模型层(核心):

     V层-视图层:

    VM层 -视图模型:VM层不是我们自己来实现的,vue就是一个VM层,它使数据变化V层也跟着变。vue会监听到数据变了,然后帮你去改变视图层;vue也能监听到视图层有事件触发,然后帮助你通过VM这一层调用你写的逻辑代码,通过这些代码改变了M层的数据-->



<!-- 关于VM层:虚拟DOM和defineProperty实现了VM层的这种架构体系,课后自行补充学习 

浅探MVVM模式实现原理:https://www.jiawin.com/p/16074-->

2_5前端组件化

<!-- 2-5前端组件化 -->
<!-- 理解:每一个组件就是页面上的一个区域 -->
<!-- 如果没有组件化,需要把代码都写到一个页面的业务逻辑,维护难 -->
<!-- 合理地拆分组件,把一个大型的项目像拼积木一样拼接起来 -->

2_6使用组件改造TodoList

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>TodoList</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- 

    <div id="app">

      <input type="text" v-model="inputValue" />

       <button v-on:click="handleBtnClick">提交</button>

      <ul>

         <todo-item v-for="item in list"></todo-item>

        每增加一个list就多一次循环就多显示一个TodoItem组件 

       Tips:TodoItem组件可以写成小写字母,驼峰命名的驼峰用-分隔: <todo-item></todo-item> 

       </ul>

    </div> -->



    <!-- <script>

      Vue.component("TodoItem", {

        template: "<li>todo item</li>",

      }); //创建一个全局组件,组件名字是TodoItem,内容是li标签、里面是todo item字符串

      //问题:每一次输入都是显示todo item

      //问题解决:todo-item相当于子组件,需要传递内容给子组件



      var app = new Vue({

        el: "#app",

        data: {

          list: [],

          inputValue: "", //双向数据绑定

        },

        methods: {

          handleBtnClick: function () {

            this.list.push(this.inputValue);

            this.inputValue = "";

          },

        },

      });

    </script> -->



    <!-- 第一种使用组件的方式(全局组件) -->

    <!-- 父组件向子组件传值 -->

    <!-- 解决以上问题如下 -->

    <div id="app">

      <input type="text" v-model="inputValue" /><!-- 双向数据绑定 -->

      <button v-on:click="handleBtnClick">提交</button>

      <ul>

        <!-- v-bind:向组件传递一个绑定值 -->

        <todo-item v-bind:content="item" v-for="item in list"></todo-item>

        

        <!-- list里面的item通过content这个变量传给todo-item -->

        <!-- 每增加一个list就多一次循环就多显示一个TodoItem组件 

        Tips:TodoItem组件可以写成小写字母,驼峰命名的驼峰用-分隔: <todo-item></todo-item>  -->

      </ul>

    </div>



    <script>

      ///在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例。在 Vue 中注册组件很简单:

      Vue.component("TodoItem", {

        props: ["content"],//TodoItem要使用父组件传递过来的数据,一点要在props里对content进行接收

        template: "<li>{{content}}</li>",

      }); //创建一个全局组件,组件名字是TodoItem,内容是li标签、里面是todo item字符串

      //这个li模板里面用到了content,组件就会把content渲染出来

      //问题:每一次输入都是显示todo item

      //问题解决:TodoItem相当于子组件,需要传递内容给子组件



      var app = new Vue({

        el: "#app",

        data: {

          list: [],

          inputValue: "", //双向数据绑定

        },

        methods: {

          handleBtnClick: function () {

            this.list.push(this.inputValue);

            this.inputValue = "";

          },

        },

      });

    </script>

  </body>

</html>

<!-- 父组件向子组件传值 -->
<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>TodoList</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- 第二种使用组件的方式(局部组件) -->

    <!-- 父组件向子组件传值 -->

    <div id="root">

      <input type="text" v-model="todoValue" /><!-- 双向数据绑定 -->

      <button @click="handleBtnClick">提交</button>

      <ul>

        <!-- v-bind:向组件传递一个绑定值 -->

        <todo-item v-bind:content="item" v-for="item in list"></todo-item>

        <!-- 相当于父组件的模板 -->

        <!-- list里面的item通过content这个变量传给todo-item -->

        <!-- 每增加一个list就多一次循环就多显示一个TodoItem组件 

        Tips:TodoItem组件可以写成小写字母,驼峰命名的驼峰用-分隔: <todo-item></todo-item>  -->

      </ul>

    </div>



    <script>

        //定义一个局部组件(子组件)

        var TodoItem={

            props:['content'],

            template:"<li>{{content}}</li>"

        }



//父组件实际就是Vue的实例

      var app = new Vue({

        el: "#root",

        components:{

            TodoItem:TodoItem

        },//把TodoItem组件注册到Vue实例之中,原来它叫TodoItem,在实例之中依然叫TodoItem

        //局部组件需要【注册】到Vue实例

        data: {

          list: [],

          todoValue: "", //双向数据绑定

        },

        methods: {

          handleBtnClick: function () {

            this.list.push(this.todoValue);

            this.todoValue = "";

          },

        },

      });

    </script>

  </body>

</html>

<!-- 父组件向子组件传值 -->

2_7简单的组件间传值

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>TodoList</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- 第二种使用组件的方式(局部组件) -->

    <!-- 子组件向父组件传值 -->

    <div id="root">

      <input type="text" v-model="todoValue" /><!-- 双向数据绑定 -->

      <button @click="handleBtnClick">提交</button>

      <!-- v-on:click=""简写是@click="" -->

      <ul>

        <todo-item v-bind:content="item"

                   v-for="item in list" 

                   @delete="handleItemDelete">

        </todo-item>

      </ul>

    </div>



    <script>

        var TodoItem={

            props:['content'],

            template:"<li @click='handleItemClick'>{{content}}</li>",

            methods:{

              handleItemClick:function(){

                this.$emit("delete")

              }

            }

        }



      var app = new Vue({

        el: "#root",

        components:{

            TodoItem:TodoItem

        },

        data: {

          list: [],

          todoValue: "", //双向数据绑定

        },

        methods: {

          handleBtnClick: function () {

            this.list.push(this.todoValue);

            this.todoValue = "";

          },

          handleItemDelete:function(){

            this.list=[];

          }

        }

      });

    </script>

  </body>

</html>

<!-- 子组件向父组件传值 -->

<!-- 待解决:点击子组件,父组件list全部清空。

目的是想实现点击哪一个li,父组件对应的一个list消失 -->
<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>TodoList</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- 第二种使用组件的方式(局部组件) -->

    <!-- 子组件向父组件传值 -->

    <div id="root">

      <input type="text" v-model="todoValue" /><!-- 双向数据绑定 -->

      <button @click="handleBtnClick">提交</button>

      <!-- v-on:click=""简写是@click="" -->

      <ul>

        <todo-item :content="item"

                   :index="index"

                   v-for="(item,index) in list" 

                   @delete="handleItemDelete">

        </todo-item>

                   <!--  通过v-bind向子组件传值的时候不仅穿content,而且传下标-->

                   <!-- v-on:click="delete"监听事件 -->

                   <!-- 监听子组件删除的事件 -->

                   <!-- 一旦监听到子组件被删除,就执行父组件handleItemDelete这个方法 -->

                   <!-- handleItemDelete这个方法拿到index -->



        <!-- v-bind:content=""简写是:content="" -->

      </ul>

    </div>



    <script>

        var TodoItem={

            props:['content','index'],//子组件想用这个下标,必须接收index。声明一个index,就会被子组件接收

            template:"<li @click='handleItemClick'>{{content}}</li>",

            methods:{

              handleItemClick:function(){

                this.$emit("delete",this.index)//子组件向父组件传值通过$emit向外触发事件

                //子组件被点击的时候,不但触发delete事件,同时把index作为参数带给父组件

              }

            }

        }



      var app = new Vue({

        el: "#root",

        components:{

            TodoItem:TodoItem

        },

        data: {

          list: [],

          todoValue: "", //双向数据绑定

        },

        methods: {

          handleBtnClick: function () {

            this.list.push(this.todoValue);

            this.todoValue = "";

          },

          handleItemDelete:function(index){

              //alert(index)

              //handleItemDelete这个方法拿到index

            this.list.splice(index,1)

          }

        //   一旦监听到子组件被删除,就执行父组件handleItemDelete这个方法,所以在父组件里定义handleItemDelete这个方法

        }

      });

    </script>

  </body>

</html>

<!-- 子组件向父组件传值 -->

<!-- 实现了点击哪一个li,父组件对应的一个list消失 -->

3_1Vue实例

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue实例</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

      <div @click="handleClick">

        {{message}}

      </div>

      <item></item>

    </div>



    <script>

      Vue.component("item", {

        template: "<div>hello world</div>",

      });

// 实际上,当我们在创建一个组件的时候,Vue的底层也会把这个组件编译成一个Vue的实例

// 也可以这样理解:一个Vue的项目由很多个组件组成,也可以理解成一个Vue的项目是由很多个Vue的实例拼装组成的。【组件化】



      var vm = new Vue({

        el: "#root",

        data: {

          message: "hello item",

        },

        methods: {

          handleClick: function () {

            alert("hello");

          },

        },

      });

    </script>

  </body>

</html>

<!-- 3_1Vue实例 -->

<!-- 理解:其实,每个组件也是一个Vue的实例,Vue实例里有很多实例属性,方法($调用,如:vm.$data) -->

3_2Vue实例生命周期

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue实例生命周期函数</title>

    <script src="../vue.js"></script>

  </head>

  <body>

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

    <script>

      //生命周期函数就是Vue实例在某一个时间点会自动执行的函数

      //在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例

      var vm=new Vue({

        el:"#app",

        template:"<div>{{test}}</div>",

        data:{

          test:"hello world"

        },

        beforeCreate:function(){

          console.log("beforeCreate");

        },

        created:function(){

          console.log("created");

        },

        beforeMount:function(){

          console.log(this.$el);

          console.log("beforeMount");

        },

        mounted:function(){

          console.log(this.$el);

          console.log("mounted");

        },

        beforeDestroy:function(){

          console.log("beforeDestroy");

        },

        destroyed:function(){

          console.log("destroyed");

        },

        beforeUpdate:function(){

          console.log("beforeUpdate");

        },

        updated:function(){

          console.log("updated");

        }

      })

    </script>

  </body>

</html>



<!-- 3_2实例生命周期钩子 -->

<!-- 生命周期函数就是Vue实例在某一个时间点会自动执行的函数 -->

<!-- 函数不放在methods里,而是直接放在Vue实例里 -->

<!-- 以上是8个,一共有11个生命周期函数 -->

3_3模板语法

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>模板语法</title>

    <script src="../vue.js"></script>

  </head>

  <body>

      <div id="app">

          <div>{{name}}</div>

          <div v-text="name+' Lee'"></div>

          <div v-html="name+'Lee'"></div>

          <!-- 凡是【v-**】指令后面的内容都是一个js表达式,在表达式里面,不仅可以写name这个变量,还可以在后面可以加字符串 -->

          <!-- 插值表达式不显示标题h1样式,v-text不显示标题h1样式,v-html显示标题h1样式 -->

      </div>

      <script>

          var vm=new Vue({

              el:"#app",

              data:{

                  name:"Dell"

                  //name:"<h1>Dell</h1>"

              }

          })

      </script>

  </body>

</html>

<!-- 这节课讲了3个模板语法 :插值表达式、v-text和v-html。

    当然Vue里面还有其他一些可以绑定在模板上面的语法,比如:v-on:click="handleClick"   v-bind:title="name"等,都是Vue的模板语法-->

3_4计算属性,方法与侦听器

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8">

    <title>3_41计算属性,方法与侦听器--计算属性</title>

    <script src="../vue.js"></script>

  </head>

  <body>

      <div id="app">

          {{fullName}}

          {{age}}

      </div>



      <script>

          var vm=new Vue({

              el:"#app",

              data:{

                  firstName:"Dell",

                  lastName:"Lee",

                  age:28

              },

              //计算属性

              computed:{

                  fullName:function(){

                      console.log("计算了一次")

                      //`this` 指向 vm 实例

                      return this.firstName+" "+this.lastName

                  }

//【计算属性--缓存机制】firstName或lastName发生改变,计算属性会重新计算一次,控制台会再输出一次“计算了一次”;如果firstName或lastName没有发生变化,只是age发生变化,计算属性不会“计算了一次”

              }

          })

      </script>

  </body>

</html>

<!-- 计算属性 -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>3_42计算属性,方法与侦听器--方法</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="app">

        <!-- 方法形式fullName后面加括号 -->

      {{fullName()}} 

      {{age}}

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data: {

          firstName: "Dell",

          lastName: "Lee",

          age: 28,

        },

        //方法

        methods: {

          fullName: function () {

            console.log("计算了一次");

            return this.firstName + " " + this.lastName;

            //【方法】firstName或lastName发生改变,会重新计算一次,控制台会再输出一次“计算了一次”;如果firstName或lastName没有发生变化,只是age发生变化,控制台也会再输出一次“计算了一次”

          },

        },

      });

      //               //计算属性

      //               computed:{

      //                   fullName:function(){

      //                       console.log("计算了一次")

      //                       return this.firstName+" "+this.lastName

      //                   }

      // //firstName或lastName发生改变,计算属性会重新计算一次,控制台会再输出一次“计算了一次”;如果firstName或lastName没有发生变化,只是age发生变化,计算属性不会“计算了一次”

      //               }

    </script>

  </body>

</html>

<!-- 方法 -->

<!-- 同样一个功能,计算属性对比方法形式,计算属性有缓存机制性能更高 -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>3_43计算属性,方法与侦听器--侦听器</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="app">

      {{fullName}} {{age}}

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data: {

          firstName: "Dell",

          lastName: "Lee",

          fullName:"Dell Lee",

          age: 28,

        },

        watch:{

            firstName:function(){

                console.log("计算了一次");

                this.fullName=this.firstName+" "+this.lastName;

            },

            lastName:function(){

                console.log("计算了一次");

                this.fullName=this.firstName+" "+this.lastName;

            }

        //【侦听器】firstName或lastName发生改变,计算属性会重新计算一次,控制台会再输出一次“计算了一次”;如果firstName或lastName没有发生变化,只是age发生变化,计算属性不会“计算了一次”

        }

      })



    </script>

  </body>

</html>

<!-- 侦听器 -->

<!-- 侦听器和计算属性性能类似,但是代码比计算属性复杂 -->

<!-- 如果一个功能既可以通过watch[侦听器]方法,也可以通过methods[方法]方法 或者是computed[计算属性]方法实现,优先推荐使用computed[计算属性],因为computed既简洁同时性能又高-->

3_5计算属性的getter和setter

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>计算属性的setter和getter</title>

    <script src="../vue.js"></script>

  </head>

  <body>

      <div id="app">

          {{fullName}}

      </div>



      <script>

          var vm=new Vue({

              el:'#app',

              data:{

                  firstName:"Dell",

                  lastName:"Lee"

              },

              computed:{

                  fullName:{

                      get:function(){

                      return this.firstName+" "+this.lastName

                      },

                      set:function(value){

                          var arr=value.split(" ");

                          this.firstName=arr[0];

                          this.lastName=arr[1];

                      }

                  }

              }

          })

      </script>

  </body>

</html>

<!-- 3_5计算属性的getter和setter -->

<!-- computed计算属性不仅可以写get方法,通过其他的值算出一个新值。同时,也可以写set方法,通过设置一个值来改变它相关联的值,而改变了它相关联的值后又会fullName引起重新计算,页面也跟着变化成新的内容 -->

<!-- 以上代码,在控制台输入vm.fullName="Mike Zhang",页面会跟着变化为Mike Zhang;然后在控制台输入vm.lastName="Li",面会跟着变化为Mike Li-->

3_6Vue中的样式绑定

1.①

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>3_6Vue中的样式绑定</title>

    <script src="../vue.js"></script>

    <style>

        .activated{color: red;}

    </style>

  </head>

  <body>

<!-- class的对象绑定 -->

<!-- class的对象绑定 :通过class和对象的形式作样式和数据绑定 -->

<!-- 对象:{activated:isActivated}   class:activated -->



    <div id="app">

        <div @click="handleDivClick"

            :class="{activated:isActivated}">

        Hello world

    </div>

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            isActivated:false

        },

        methods:{

            handleDivClick:function(){

                this.isActivated=!this.isActivated;

            }

        }

      });

    </script>

  </body>

</html>

1.②

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>3_6Vue中的样式绑定</title>

    <script src="../vue.js"></script>

    <style>

        .activated{color: red;}

    </style>

  </head>

  <body>

<!-- class的数组绑定 -->

<!-- 通过数组 -->

    <div id="app">

        <!-- 读代码:div元素会显示一个class,class是数组activated这个变量的内容 -->

        <div @click="handleDivClick"

            :class="[activated,activatedOne]">

        Hello world

    </div>

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            activated:"",

            activatedOne:"activatedOne"

        },

        //刚开始页面div class只会有"activatedOne",没有activated

        methods:{

            handleDivClick:function(){

                // if(this.activated==="activated"){

                //     this.activated=""

                //     }else{

                //         this.activated="activated"

                //     }

                    this.activated=this.activated==="activated"?"":"activated"  

            }

        }

      });

    </script>

  </body>

</html>

2.①

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>3_6Vue中的样式绑定</title>

    <script src="../vue.js"></script>

  </head>

  <body>

<!-- style-->

<!-- 除了class,还可以用style来改变样式 -->

<!-- 通过对象进行绑定 -->

<!-- 这里(直接写内联样式 ) -->

    <div id="app">

        <div :style="styleObj" @click="handleDivClick"> 

            Hello world

        </div>

        <!-- styleObj是一个对象 -->

    </div>

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            styleObj:{

                color:"black"

            }

        },

        methods:{

            handleDivClick:function(){

                this.styleObj.color=this.styleObj.color==="black"?"red":"black";

            }

        }

      });

    </script>

  </body>

</html>

<!-- style -->

2.②

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>3_6Vue中的样式绑定</title>

    <script src="../vue.js"></script>

  </head>

  <body>

<!-- style->

<!-- 通过数组进行绑定(不再是个对象) -->

<!-- 这里(直接写内联样式 ) -->

    <div id="app">

        <div :style="[styleObj,{fontSize:'20px'}]" @click="handleDivClick"> 

            Hello world

        </div>

    </div>

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            styleObj:{

                color:"black"

            }

        },

        methods:{

            handleDivClick:function(){

                this.styleObj.color=this.styleObj.color==="black"?"red":"black";

            }

        }

      });

    </script>

  </body>

</html>

<!-- style -->

3_7Vue中的条件渲染

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的条件渲染</title>

    <script src="../vue.js"></script>

  </head>

  <body>



    <div id="app">

        <div v-if="show" data-test="v-if">{{message}}</div>

        <div v-show="show" data-test="v-show">{{message}}</div>

    </div>

<!-- v-if=""冒号里面使js表达式,根据js表达式的返回值决定这个标签是否在页面上存在 -->

<!-- v-if和v-show都能控制模板标签是否在页面上显示,

    区别是:

    v-if对应的js表达式值是false的时候,这个标签不存在DOM之上;

    而 v-show是false的时候,这个标签对应的DOM在页面上依然存在,只不过以display:none;的形式-->

<!-- v-show性能更高,因为它不会频繁地把一个DOM从页面上删除再添加 ,v-if每次显示和隐藏相当于都是删除DOM再增加DOM,所以v-if性能较低一些-->

    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            show:false,

            message:"Hello World"

        }

      });

    </script>

  </body>

</html>

    <!-- Vue中的条件渲染     -->

    <!-- 注意,v-show 不支持 <template> 元素,也不支持 v-else。 -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的条件渲染</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="app">

        <div v-if="show">{{message}}</div>

        <div v-else>Bye World</div>

        <!-- v-if和v-else要连在一起写,不能这样写:<div v-if="show">{{message}}</div>

        <span></span>

        <div v-else>Bye World</div> -->

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            show:false,

            message:"Hello World"

        }

      });

    </script>

  </body>

</html>

    <!-- Vue中的条件渲染     -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的条件渲染</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="app">

        <div v-if="show==='a'">This is A</div>

        <div v-else-if="show==='b'">This is B</div>

        <div v-else>This is others</div>

        <!-- v-if和v-else要连在一起写,不能这样写:<div v-if="show">{{message}}</div>

        <span></span>

        <div v-else>Bye World</div> -->

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            show:"b",

        }

      });

    </script>

  </body>

</html>

    <!-- Vue中的条件渲染     -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的条件渲染</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="app">

        <div v-if="show">

            用户名:<input type="text" key="username">

        </div>

        <div v-else>

            邮箱名:<input type="text" key="password">

        </div>

<!-- 不加上key值的话,控制台输入vm.show=true回车后,[邮箱:]变成[用户名:] ,但是input框里面之前输入的内容没有被清空-->

<!-- 加上key值,Vue知道是唯一的,不会尝试去复用以前的input标签了,input框里面之前输入的内容被清空,虚拟DOM算法内容…… -->

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            show:false,

        }

      });

    </script>

  </body>

</html>

    <!-- Vue中的条件渲染     -->

3_8Vue中的列表渲染

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的列表渲染</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- 数组的循环 -->

    <div id="app">

        <!-- item of list可以,更推荐用of,因为它更接近 JavaScript 迭代器的语法 -->

        <div v-for="(item,index) of list">

            {{item}}---{{index}}

        </div>

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            list:[

            "hello",

            "dell",

            "nice",

            "to",

            "meet",

            "you"

        ]

    }

      });

    </script>

  </body>

</html>

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的列表渲染</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- 对数组作循环 -->

    <div id="app">

        <!-- item of list可以,更推荐用of -->

        <!-- key要是唯一的,但不推荐用index作为key值,因为后端返回的data是……**形式 (为了提高循环的性能一般加唯一的key值)用index的话在你频繁操作DOM元素相对应的数据其实还是比较费性能,它可能让Vue没有充分地复用DOM节点。



          一般后端向前端返回数据的时候,也就是list不是前端写死的一个数组list:["hello","dell","nice","to","meet","you"],后端返数据的时候一般会携带一个跟数据库或后端相关的一个唯一的数据条文标识符,一般这个东西会叫做id,[id:"010120201"]它可能是数据库相对应的一个字段,这个值是这个数据的唯一标识,同时也会返回数据的内容[text:"hello"]  

        如何使性能较高:key值(item.id)既是唯一的,也不是index下标-->

        <div v-for="(item,index) of list":key="item.id">

            {{item.text}}---{{index}}

            <!-- 这里是要加上.text -->

        </div>

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data:{

            list:[{

                id:"010120201",

                text:"hello"

            },{

                id:"010120202",

                text:"Dell"

            },{

                id:"010120203",

                text:"Lee"

            }

        ]

    }

      });

    </script>

  </body>

</html>

<!-- 操作数组的变异方法(七个):

  push pop shift unshift splice sort reverse -->



<!-- 控制台输入:vm.list[1]={id:"333",text:"Dell"}

    控制台返回:{id:"333",text:"Dell"}

    控制台输入:vm.list

    控制台返回:0:{_ob_:Observer}

              1:{id:"333",text:"Dell"}

              2:{_ob_:Observer}

              length:3

    但是页面无变化(即直接修改数组下标的内容无法让页面跟着响应)

  

  如何来做?

  (1)

  控制台输入:vm.list.splice(1,1,{id:"333",text:"Dell1111"})

  页面发生变化【通过变异方法操作数组,数据发生变化页面也就会变了】



   (2)

  除了【变异方法】,还有一种方法是【改变引用】

  

  数组在js里面使一个引用类型,把list引用改变了,页面也会跟着变动。

  让vm.list=一个新的引用

  控制台输入:vm.list=[{

                id:"010120201",

                text:"hello"

            },{

                id:"010120202",

                text:"Dell1111"

            },{

                id:"010120203",

                text:"Lee"

            }

        ]

    操作list的引用,让它指向另外的地址空间,回车后,数据变了页面也跟着变化[改变数据的引用地址从而实现]

    -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的列表渲染</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- 对数组作循环【补充知识点--template】 -->

    <div id="app">

      <!-- 想要加一个span一起循环,让循环执行2次不靠谱,接着【下面看】

        <div v-for="(item,index) of list"

             :key="item.id">

            {{item.text}}---{{index}}

        </div>

        <span v-for="(item,index) of list"

              :key="item.id">

            {{item.text}}

        </span> -->



      <!-- 【接上面】

      在外层用一个div包裹一次循环,查看器显示外层div

    <div v-for="(item,index) of list" :key="item.id">

      <div>

        {{item.text}}---{{index}}

      </div>

      <span>

        {{item.text}}

      </span>

    </div> -->



    <!-- 【接上面】假设需求是外层div不用不出现:用【template】 -->

    <template v-for="(item,index) of list" :key="item.id">

        <div>

          {{item.text}}---{{index}}

        </div>

        <span>

          {{item.text}}

        </span>

      </template>

<!-- 查看器没有显示template

    template作用:模仿占位符,帮助我们去包裹一些元素,但在循环的过程中它并不会被真正地渲染到页面上 -->



    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data: {

          list: [

            {

              id: "010120201",

              text: "hello",

            },

            {

              id: "010120202",

              text: "Dell",

            },

            {

              id: "010120203",

              text: "Lee",

            },

          ],

        },

      });

    </script>

  </body>

</html>

<!-- template作用:模仿占位符,帮助我们去包裹一些元素,但在循环的过程中它并不会被真正地渲染到页面上 -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的列表渲染</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- 对对象作循环 -->

    <div id="app">

      <!-- 需求:把对象的内容循环展示在页面上 -->

      <div v-for="(item,key,index) of userInfo">

        {{item}}--{{key}}--{{index}}

      </div>



      <!-- {{item}}--{{key}}--{{index}}的意思是(页面显示):

     Dell--name--0

     28--age--1

     male--gender--2

     secret--salary--3

      -->



      <!-- 控制台输入:vm.userInfo.name="Dell lee",

            页面的name的值也会变,



         [加一项address]

         控制台输入:vm.userInfo.address="beijing",

         [确认数据有没有变]

         控制台再输入:vm.userInfo

         显示有数据(数据变了页面没变)



         当你去遍历对象的时候,如果动态地往这个对象去加值往往是不好用的嘻嘻嘻嘻嘻~~~~~~

        

         就想加的话↓

        【改引用的方法】(和数组类似):

        控制台输入:

        vm.userInfo={

                name:"Dell",

                age:28,

                gender:"male",

                salary:"secret"

                address:"beijing"

            }

        这时页面会变,加多了一项address

       vm.userInfo数据的引用换成了一个全新的对象

      -->

    </div>



    <script>

      var vm = new Vue({

        el: "#app",

        data: {

          //一个对象的数据结构

          userInfo: {

            name: "Dell",

            age: 28,

            gender: "male",

            salary: "secret",

          },

        },

      });

    </script>

  </body>

</html>

3_9Vue中的set方法

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的set方法</title>

    <script src="../vue.js"></script>

  </head>

  <body>



    <div id="app">

      <div v-for="(item,key,index) of userInfo">

        {{item}}--{{key}}--{{index}}

      </div>

    </div>

<!--(1)【对象中set方法的使用】

    set方法① 

    控制台输入:Vue.set(vm.userInfo,"address","beijing")

     回车 控制台返回:"beijing"

    页面显示:

     Dell--name--0

     28--age--1

     male--gender--2

     secret--salary--3

     beijing--address--4

    

    set方法②

    [set方法既是Vue上的一个全局方法,也是Vue的实例方法]

    控制台输入:vm.$set(vm.userInfo,"address","beijing")

     回车 控制台返回:"beijing"

         页面显示:

     Dell--name--0

     28--age--1

     male--gender--2

     secret--salary--3

     beijing--address--4

    

    

     (2)【数组中set方法的使用见下一个html文件3_92.html】

    

    -->







    <script>

      var vm = new Vue({

        el: "#app",

        data: {

          //一个对象的数据结构

          userInfo: {

            name: "Dell",

            age: 28,

            gender: "male",

            salary: "secret",

          },

        },

      });

    </script>

  </body>

</html>

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的set方法</title>

    <script src="../vue.js"></script>

  </head>

  <body>



    <div id="app">

      <div v-for="(item,key,index) of userInfo">

        {{item}}

      </div>

    </div>

<!--

    

     (2)【数组中set方法的使用见下一个html文件3_92.html】

    [向数组加入一个数据前面讲的方法有变异方法和改变引用]

    [set方法可以改变数组中的每一项]



    控制台输入:vm.userInfo[1]=5

    数组数据发生了变化,但是页面没有跟着变化



    set方法解决这个问题:

    ①直接Vue.

    控制台输入:Vue.set(vm.userInfo,1,5)

回车 控制台返回:5  ;页面的第2项(也就是数组下标为1的项)变成5

    ②Vue的实例方法

    控制台输入:vm.$set(vm.userInfo,2,10)

回车 控制台返回:10  ;页面的第3项(也就是数组下标为2的项)变成10

    -->



    <script>

      var vm = new Vue({

        el: "#app",

        data: {

          userInfo: [1,2,3,4],

        },

      });

    </script>

  </body>

</html>

<!-- 复习3_8Vue中的列表渲染、3_9Vue中的set方法 -->

<!-- 

    1、在Vue中实现数组改变页面跟着变的方法:

  (1)直接改变数组的引用

   (2)调用数组的变异方法

  (3)set方法(①Vue.和②vm.)



   2、实现改变对象里的数据页面跟着改变的方法:

  (1)直接改变对象的引用

  (2)set方法(①Vue.和②vm.)-->

4_1使用组件的细节点

1.①

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>组件中的细节点</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root">

        <table>

            <tbody>

                <row></row>

                <row></row>

                <row></row>

            </tbody>

        </table>

        <!-- 浏览器显示没问题,但是在显示器里3个tr下面才是 <table></table>,是因为H5规范中tbody里面必须放tr,row的解析出了问题-->

        <!-- 问题解决见[4_12.html] -->

    </div>



    <script>



Vue.component('row',{template:'<tr><td>this is a row</td></tr>'})



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>

<!-- 使用is解决H5标签的一些小bug -->

1.②

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>组件中的细节点</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root">

        <table>

            <tbody>

              <tr is="row"></tr>

              <tr is="row"></tr>

              <tr is="row"></tr>

            </tbody>

        </table>

    </div>

    <!-- 此时查看器,div里面有table,table里面有3个tr -->



    <!-- 遇到这种组件上的小bug可以使用is来解决 -->

<!-- 以下情况和以上一样写~~~~~ -->

    <!-- ""双引号里写组件的名字

      <ul><li is=""></li></ul>

      <ol><li is=""></li></ol>

    <select><option is=""></option></select> -->



    <script>



Vue.component('row',{template:'<tr><td>this is a row</td></tr>'})



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>

<!-- 使用is解决H5标签的一些小bug -->

<!-- is=""(双引号里写组件的名字)解决组件上的小bug -->

2.①

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>组件中的细节点</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root">

        <table>

            <tbody>

              <tr is="row"></tr>

              <tr is="row"></tr>

              <tr is="row"></tr>

            </tbody>

        </table>

    </div>





    <script>



Vue.component('row',{

    // data:{

    //     content:'this is a row'

    // },

    // //报错:[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.

    // //这里data必须要是个函数

    // //在实例中的data可以这样写



    data:function(){

        return {

            content:'this is content'

        }

    },

    template:'<tr><td>{{content}}</td></tr>'})



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>

<!-- 在子组件定义data必须是一个函数,而不能是一个对象,之所以这么设计,是因为子组件不像根组件只会被调用一次,例如上面就被调用了3次,每一个子组件都应该有自己的数据,通过函数来调用就是让每一个子组件都拥有独立的数据存储 -->

3.①

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>组件中的细节点</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <!-- <div id="root">

        <div 

             @click="handleClick">

         hello world

        </div>

    </div>





    <script>



      var vm = new Vue({

        el: "#root",

        methods:{

            handleClick:function(){

                alert('click')

            }

        }

      });



    </script> -->



<div id="root">

    <div 

         ref='hello'

         @click="handleClick">

     hello world

    </div>

</div>





<script>



  var vm = new Vue({

    el: '#root',

    methods:{

        handleClick:function(){

            //获取DOM元素

            alert(this.$refs.hello.innerHTML)

        }

    }

  });



</script>

  </body>

</html>

<!-- ref的使用 -->

3.②

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>组件中的细节点</title>

    <script src="../vue.js"></script>

  </head>

  <body>



    <div id="root">

      <counter ref="one" @change="handleChange"></counter>

      <counter ref="two" @change="handleChange"></counter>

      <div>{{total}}</div>

    </div>



    <script>

      Vue.component("counter", {

        template: '<div @click="handleClick">{{number}}</div>',

        data: function () {

          return {

            number: 0,

          };

        },

        methods: {

          handleClick: function () {

            this.number++;

            this.$emit('change')

          }

        }

      });



      var vm = new Vue({

        el: "#root",

        data:{

            total:0

        },

        methods:{

            handleChange:function(){

                this.total=this.$refs.one.number+this.$refs.two.number

                // console.log(this.$refs.one.number)

                // console.log(this.$refs.two.number)

            }

        }

      });

    </script>

  </body>

</html>

<!-- ref的使用 -->

<!-- 做了一个counter求和的功能 -->

<!-- 主要是理解ref的使用 -->

<!-- 当ref写在<div></div>标签里面的时候 ,通过[this.$refs.名字]获取到的内容实际上是标签对应的DOM元素,而当你在一个组件上写ref,然后通过[this.$refs.名字]获取ref里面的内容的时候,这个时候你获取到的内容实际是counter这个子组件的引用-->

4_2父子组件间的数据传递

1.①i

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>父子组件传值</title>

    <script src="../vue.js"></script>

  </head>

  <body>



    <div id="root">

        <!-- :count="0"加上双引号,""里面是js表达式,0是数据类型,不再是一个字符串-->

        <counter :count="0"></counter>

        <counter :count="1"></counter>

    </div>

    <!-- 父组件向子组件传值通过属性的形式 -->



    <script>



var counter={

    props:['count'],

    template:'<div @click="handleClick">{{count}}</div>',

    methods:{

        handleClick:function(){

            this.count++

        }

    }

}

//页面可以正常显示,控制台:[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "count"

// found in



// ---> <Counter>

//        <Root>



//[不要在子组件里直接修改父组件传递过来的数据]

//Vue中有一个【单向数据流】的概念,也就是父组件可以通过属性的方式向子组件传递参数,你传递的参数可以随便的修改没有问题;子组件不能反过来去修改父组件传递过来的这个参数,子组件只能去用这个参数。



//之所以Vue之中有这个【单向数据流】的概念,是因为一旦子组件接收的这个count并不是基础类型的数据,而是Object对象形式也就是引用类型的时候,你在子组件里面改变了传递过来的内容的话,有可能接收的这个引用型的数据还被其他的子组件所使用的,改了数据的话不仅仅影响这个一个组件,也可能对其他的组件造成影响。



      var vm = new Vue({

        el: "#root",

        //注册子组件

        components:{

            counter:counter

        }

      })

    </script>

  </body>

</html>

<!-- 父组件向子组件传递数据 -->

<!-- 不能在子组件里直接修改父组件传递过来的数据,需要count++那怎么办,解决办法见下一个html(4_22a.html) -->

2.①i

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>父子组件传值</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

      <counter :count="0"></counter>

      <counter :count="1"></counter>

    </div>



    <script>

      var counter = {

        props: ['count'],

        data: function () {

          return {

            number: this.count

          }

        },

        template: '<div @click="handleClick">{{number}}</div>',

        methods: {

          handleClick: function () {

            this.number++;

          },

        },

      };



      var vm = new Vue({

        el: "#root",

        //注册子组件

        components: {

          counter: counter,

        },

      });

    </script>

  </body>

</html>

<!-- 父组件向子组件传递数据 -->

<!-- 不能在子组件里直接修改父组件传递过来的数据,需要count++那怎么办,解决办法如上:

        data: function () {

          return {

            number: this.count

          }

        },

        template: '<div @click="handleClick">{{number}}</div>',

         methods:{

        handleClick:function(){

            this.number++

        }

    }-->

<!-- 父组件通过属性的形式向子组件传值[单向数据流]

    一定要修改,拷贝副本出来再修改 -->

3.①

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>父子组件传值</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

      <counter :count="3" @inc="handleIncrease"></counter>

      <counter :count="2" @inc="handleIncrease"></counter>

      <div>{{total}}</div>

    </div>



    <script>

      var counter = {

        props: ['count'],

        data: function () {

          return {

            number: this.count

          }

        },

        template: '<div @click="handleClick">{{number}}</div>',

        methods: {

          handleClick: function () {

            this.number=this.number+2;

            this.$emit('inc',2)

          },

        },

      };



      var vm = new Vue({

        el: "#root",

        data:{

            total:5

        },

        //注册子组件

        components: {

          counter: counter,

        },

        methods:{

            handleIncrease:function(step){

                this.total+=step

            }

        }

      });

    </script>

  </body>

</html>

<!-- 子组件向父组件传递数据 -->

<!-- 子组件通过事件触发的形式向父组件传值 -->

<!-- 父组件通过属性的形式向子组件传值[单向数据流]

    一定要修改的话,拷贝副本出来再修改 -->

4_3组件参数校验与非pros特性

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>组件参数校验与非Props特性</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root">

        <child :content="123"></child>

        <!--这样写123仍然是字符串: 

            <child content="123"></child>

        123是数字这样写:

        <child :content="123"></child>-->

    </div>



    <script>

        Vue.component('child',{

            //content:String如果不是字符串控制台有报错

            // props:{

            //     content:[Number,String]//Number或者String

            // },



            props:{

                content:{

                    type:String,



//content可以不必传,required:true是content要有内容传过来

                    required:false,



//如果属性content没有,会使用default的默认值'default value';如果content有,就显示content的内容                   

                    default:'default value',



                    validator:function(value){

                        return (value.length>5)

                    }

                    





                }

            },

            template:'<div>{{content}}</div>'

        })



      var vm = new Vue({

        el: '#root',

      });

    </script>

  </body>

</html>



<!-- 组件参数校验 -->

2.①

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>组件参数校验与非Props特性</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root">

        <child :content="123"></child>

    </div>



    <script>

        Vue.component('child',{

            // props:{

            //     content:{

            //         type:String,

   

            //         default:'default value',



            //         validator:function(value){

            //             return (value.length>5)

            //         }

                    

            //     }

            // },

            template:'<div>{{content}}</div>'

        })



      var vm = new Vue({

        el: '#root',

      });

    </script>

  </body>

</html>

<!-- 【props特性】

【props:{}没有被注释的情况】

当父组件使用子组件的时候,通过属性向子组件传值,恰好子组件声明了对父组件传递过来的属性的接收 

①这个属性(content="123")不会在DOM标签上显示

此时DOM标签:<div>{{content}}</div>

而不是:<div content="123">{{content}}</div>

②在子组件可以通过插值表达式({{content}})或者this.content去取得content的内容-->



<!-- 【非props特性】

【props:{}被注释掉的情况】

(a)父组件向子组件传递了一个属性,但是子组件没有props:{}这块的内容来接收--控制台报错content没有被定义

(b)以上代码页面显示hello,

查看器显示<div content="hell">hello</div> 

即第二个非Props特性,这个属性会展示在子组件最外层的DOM标签的

HTML属性里面



(第二个非props特性见下一个html文件4_32b.html)-->

2.②

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>组件参数校验与非Props特性</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root">

        <child :content="hell"></child>

    </div>



    <script>

        Vue.component('child',{

            // props:{

            //     content:{

            //         type:String,

   

            //         default:'default value',



            //         validator:function(value){

            //             return (value.length>5)

            //         }

                    

            //     }

            // },

            template:'<div>hello</div>'

        })



      var vm = new Vue({

        el: '#root',

      });

    </script>

  </body>

</html>



<!-- 非props特性

(a)父组件向子组件传递了一个属性,但是子组件没有props:{}这块的内容来接收--控制台报错content没有被定义

(b)以上代码页面显示hello,

查看器显示<div content="hell">hello</div> 

即第二个非props特性,这个属性会展示在子组件最外层的DOM标签的HTML属性里面



(第一个非props特性见上一个html文件4_32a.html)-->

4_4给组件绑定原生事件

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>给组件绑定原生事件</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- <div id="root">

        <child @click="handleClick"></child>

    </div>



    <script>



      Vue.component('child',{

          template:'<div>Child</div>'

      })



      var vm = new Vue({

        el: "#root",

        methods:{

            handleClick:function(){

                alert('click')

            }//handleClick不能执行,页面点击Child弹不出'click'

      });

    </script> -->



<div id="root">

    <child @click="handleClick"></child>

    <!-- 父组件监听到click 执行handleClick-->

</div>



<script>



  Vue.component('child',{

      template:'<div @click="handleClick">Child</div>',

      methods:{

        handleClick:function(){

            this.$emit('click')//向外触发一个自定义事件

        }

      }

  })

// 页面上点击Child的时候,子组件会监听到自身的div元素被点击了,然后会向外触发一个自定义事件'click',而在父组件里监听了这个自定义事件'click',所以对应的Vue实例的handleClick就会被执行。







  var vm = new Vue({

    el: "#root",

    methods:{

        handleClick:function(){

            alert('click')

        }

    }

  });

</script>

  </body>

</html>

<!-- 像上面这样写代码实在是太麻烦了,有的时候就想监听我原生的一个事件,比如在<child></child>组件上监听<child>组件的原生事件 ,做法见下一个html文件(4_42.html)-->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>给组件绑定原生事件</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

      <child @click.native="handleClick"></child>

      <!-- 监听的不是自定义事件了,是一个原生事件 -->

    </div>



    <script>

      Vue.component("child", {

        template: '<div>Child</div>',

      });



      var vm = new Vue({

        el: "#root",

        methods: {

          handleClick: function () {

            alert("click");

          }//页面点击ChildhandleClick可以被执行、弹出"click"

        },

      });

    </script>

  </body>

</html>

<!-- 给组件绑定原生事件:事件绑定的后面加一个native修饰符,

如上面:@click.native="handleClick" -->

4_5非父子组件的传值

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>非父子组件间传值(Bus/总线/发布订阅模式/观察者模式)</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

      <child content="Dell"></child>

      <child content="Lee"></child>

    </div>

    <!-- 页面显示

        Dell

        Lee

        想实现点击Dell,Lee变为Dell,需要进行非父子组件的传值

     -->



    <script>

      Vue.prototype.bus = new Vue();



      Vue.component("child", {

        props: {

          content: String,

        },

        template: "<div>{{content}}</div>",

      });



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>

<!-- 非父子组件的传值 -->

<!-- 想实现点击Dell,Lee变为Dell,需要进行非父子组件的传值,见下一个html文件(4_52.html) -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>非父子组件间传值(Bus/总线/发布订阅模式/观察者模式)</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

      <child content="Dell"></child>

      <child content="Lee"></child>

    </div>

    <!-- 页面显示

        Dell

        Lee

        想实现点击Dell,Lee变为Dell,需要进行非父子组件的传值

     -->



    <script>

      Vue.prototype.bus = new Vue();



      Vue.component("child", {

        props: {

          content: String,

        },

        template: '<div @click="handleClick">{{content}}</div>',

        methods:{

            handleClick:function(){

                // alert(this.content)//点击自己弹出自己的content

                //每个实例bus属性都是存在的,这个bus是Vue的实例,所以有$emit这个方法,通过这个方法向外触发事件,事件触发的时候同时携带了一个数据,就是自己的内容(this.content)

                this.bus.$emit('change',this.content)

            

            }

        },

        mounted:function(){

            var this_=this//所以这里要将this进行保存

            this.bus.$on('change',function(msg){



                // alert(msg)//一个child组件触发事件的时候,两个child组件都进行了同一个事件的监听,两个child组件都弹msg



                // this.content=msg//不行,因为this作用域(this.bus.$on那里)发生了变化



                this_.content=msg

            })

        }

      });



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>

<!-- 非父子组件的传值 -->



<!-- 页面实现了效果,但是控制台报错,因为是没有遵循单向数据流,在子组件强改了父组件传递过来的内容,

    解决办法

    参考[4_2父子组件间的数据传递]

    实现解决见下一个html文件(4_53.html) -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>非父子组件间传值(Bus/总线/发布订阅模式/观察者模式)</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

      <child content="Dell"></child>

      <child content="Lee"></child>

    </div>

    <!-- 页面显示

        Dell

        Lee

        想实现点击Dell,Lee变为Dell,需要进行非父子组件的传值

     -->



    <script>

      Vue.prototype.bus = new Vue();



      Vue.component("child", {

        data:function(){

            return {

                selfContent:this.content//作一个拷贝

            }

        },

        props: {

          content: String,

        },

        template: '<div @click="handleClick">{{selfContent}}</div>',

        methods:{

            handleClick:function(){

                this.bus.$emit('change',this.selfContent)//触发

            }

        },

        mounted:function(){

            var this_=this

            this.bus.$on('change',function(msg){//监听change

                this_.selfContent=msg

            })

        }

      });



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>



<!-- 非父子组件的传值 -->



<!-- 页面实现了效果,但是控制台报错,因为是没有遵循单向数据流,在子组件强改了父组件传递过来的内容,

    解决办法如上代码:

父组件通过属性的形式向子组件传值[单向数据流]

    一定要修改的话,拷贝副本出来再修改[selfContent] -->



    <!-- Vue.prototype.bus = new Vue();

    通过【bus总线】的形式实现了Vue之中非父子组件之间的传值,上面是一个兄弟节点(<child content="Dell"></child>

      <child content="Lee"></child>) ,如果以后遇到了非兄弟节点的非父子组件也是一样的,通过bus形式都能够解决这种复杂的组件之间传值的问题-->



<!-- 主要需要搞清楚:

①Vue.prototype.bus = new Vue();

②如何触发

③如何监听 -->



<!-- 如果之前大家js基础很好的话,会发现它就是一个简单的【发布订阅模式】或者【观察者模式】 -->

4_6在Vue中使用插槽

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的插槽(slot)</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

        <child content='<p>Dell</p>'></child>



        <!-- <child content='<p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p>'></child> 

        如果想显示那么多个Dell,这样做太多代码,解决办法见下一个html文件(4_62.html)-->



    </div>



    <script>



      Vue.component("child", {

          props:['content'],

        template: `<div>

                        <p>hello</p>

//这里是要用div包裹然后里面是一个p标签,用template不行

                        <div v-html="this.content"></div>

                    </div>`//es6语法

      })



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>



        <!-- <child content='<p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p><p>Dell</p>'></child> 

        如果想显示那么多个Dell,这样做太多代码,解决办法见下三个html文件(4_62.html4_63.html4_64.html)-->



        <!-- 解决办法:在Vue中使用插槽 (slot)-->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的插槽(slot)</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

        <child>

            <p>Dell</p>

        </child>

    </div>



    <script>



      Vue.component("child", {

        template: `<div>

                        <p>hello</p>

                        <slot>默认内容</slot>

                        //<child></child>标签里面没有东西会显示“默认内容”

                    </div>`//es6语法

      })



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>

<!-- 在Vue中使用插槽 (slot)-->

<!-- 见下一个html文件 -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的插槽(slot)</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

        <body-content>

            <div class='header'>header</div>

            <div class='footer'>footer</div>

        </body-content>

    </div>



    <script>



      Vue.component("body-content", {

        template: `<div>

                        <slot></slot>

                        <div class='content'>content</div>

                        <slot></slot>

                    </div>`//es6语法

      })



//页面显示(因为没有给插槽起名字):

// header

// footer

// content

// header

// footer



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>

<!-- 在Vue中使用插槽 (slot)-->

<!-- 见下一个html文件,下一个html文件是【具名插槽】的内容 -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的插槽(slot)</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

        <body-content>

            <div class='header' slot='header'>header</div>

            <div class='footer' slot='footer'>footer</div>

        </body-content>

    </div>



    <script>



      Vue.component("body-content", {

        template: `<div>

                        //具名插槽,也就是给插槽起一个名字

                        <slot name='header'></slot>

                        <div class='content'>content</div>

                        <slot name='footer'></slot>

                    </div>`//es6语法

      })



//页面显示【具名插槽】:

// header

// content

// footer



//具名插槽也可以有默认值:<slot name='header'><h1>default header</h1></slot>默认值为default header,

//如果没有“<div class='header' slot='header'>header</div>”这一行,就会显示默认值default header







      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>

<!-- 在Vue中使用插槽 (slot)-->

<!-- 见下一个html文件 -->

4_7作用域插槽

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的作用域插槽</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <!-- <div id="root">

      <child></child>

    </div>



    <script>

      Vue.component('child', {

        data:function() {

            return {

              list: [1, 2, 3, 4],

            };

          },



        template: `<div>

                    <ul>

                        <li v-for="item of list">

                        {{item}}

                        </li>

                    </ul>

                   </div>`,

      });



      var vm = new Vue({

        el: "#root",

      });

    </script> -->



    <div id="root">

      <child>

        <template slot-scope="props">

          <h1>{{props.item}}</h1>

        </template>

      </child>

    </div>



    <script>

      Vue.component("child", {

        data: function () {

          return {

            list: [1, 2, 3, 4],

          };

        },



        template: `<div>

                  <ul>

                      <slot v-for="item of list"

                            :item=item>

                      </slot>

                  </ul>

                 </div>`,

      });



      var vm = new Vue({

        el: "#root",

      });

    </script>

  </body>

</html>

<!-- 作用域插槽的使用 -->

<!-- 以上代码思路:

首先,父组件调用子组件的时候给子组件传了一个插槽,这个插槽叫作用域插槽,作用域插槽必须是template开头结尾,同时这个插槽要声明从子组件接收的数据要放在哪里(slot-scope="props"放在props里),同时插槽还要告诉子组件一个模板的信息(以一个h1标签的形式对数据进行展示):

        <template slot-scope="props">

          <h1>{{props.item}}</h1>

        </template>

 -->



 <!-- 什么时候使用作用域插槽?

——当子组件作循环或者某一部分DOM结构应该由外部传递进来的时候,这个时候使用作用域插槽。使用作用域插槽,子组件可以向父组件的插槽传数据,父组件传递过来的插槽如果想接收这个数据就在外层使用template同时通过slot-scope对应的属性名字来接收数据(item),父组件再使用这个数据(item) -->

4_8动态组件与v-once指令

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>动态组件与v-once指令</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root">

        <child-one v-if="type==='child-one'"></child-one>

        <child-two v-if="type==='child-two'"></child-two>

        <button @click="handleBtnClick">change</button>

    </div>



    <script>



        Vue.component('child-one',{

            template:'<div>child-one</div>'

        })



        Vue.component('child-two',{

            template:'<div>child-two</div>'

        })



      var vm = new Vue({

        el: '#root',

        data:{

            type:'child-one'

        },

        methods:{

            handleBtnClick:function(){

                this.type=this.type==='child-one'?'child-two':'child-one';

            }

        }

      });

    </script>

  </body>

</html>

<!-- 还可以通过动态组件来编写以上代码,见下一个html文件(4_82.html) -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>动态组件与v-once指令</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root">

        <component :is="type"></component>

        <!-- <child-one v-if="type==='child-one'"></child-one>

        <child-two v-if="type==='child-two'"></child-two> -->

        <button @click="handleBtnClick">change</button>

    </div>



    <script>



        Vue.component('child-one',{

            template:'<div>child-one</div>'

        })



        Vue.component('child-two',{

            template:'<div>child-two</div>'

        })



      var vm = new Vue({

        el: '#root',

        data:{

            type:'child-one'

        },

        methods:{

            handleBtnClick:function(){

                this.type=this.type==='child-one'?'child-two':'child-one';

            }

        }

      });

    </script>

  </body>

</html>

<!-- 通过动态组件来编写代码:

    <component :is="type"></component>   -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>动态组件与v-once指令</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    

    <div id="root">

        <!-- <component :is="type"></component> -->

        <child-one v-if="type==='child-one'"></child-one>

        <child-two v-if="type==='child-two'"></child-two>

        <button @click="handleBtnClick">change</button>

    </div>



    <script>



        Vue.component('child-one',{

            template:'<div v-once>child-one</div>'

        })



        Vue.component('child-two',{

            template:'<div v-once>child-two</div>'

        })



      var vm = new Vue({

        el: '#root',

        data:{

            type:'child-one'

        },

        methods:{

            handleBtnClick:function(){

                this.type=this.type==='child-one'?'child-two':'child-one';

            }

        }

      });

    </script>

  </body>

</html>

<!-- v-once指令-->



<!-- 4_8的v-if的使用实际上每一次Vue的底层都是销毁一个组件+创建一个组件,耗费了一定的性能 -->



<!-- 上面的代码在子组件模板div中加上v-once指令:

    好处:

    当childone组件第一次被渲染的时候,因为childone组件有v-once指令它直接被放在内存里,

    但我们点击按钮切换的时候childtwo第一次展示在页面的时候,有v-once指令childtwo也直接被放在内存里,

    再点击切换的时候并不需要重新创建一个childone组件,而是从内存里直接拿出以前的childone组件就可以了;

    性能会更高一些。



    在Vue中加上v-once指令有效地提高静态内容的展示效率 -->

5_1Vue动画-Vue中CSS动画原理

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中CSS动画原理</title>

    <script src="../vue.js"></script>

    <style>

        /* .fade-enter,.fade-leave-to{

            opacity:0;

        }

        .fade-enter-active,.fade-leave-active{

            transition: opacity 1s;

        } */



        /* 



//opacity: value|inherit;

//value规定不透明度。从 0.0 (完全透明)到 1.0(完全不透明)。 inherit 	应该从父元素继承 opacity 属性的值。



//【动画渐显】还没开始的时候v-enter和v-enter-active已经存在,第一帧的时候存在,opacity:0所以刚开始是隐藏状态,当,动画运行的第二帧的时候v-enter被移除,opacity自动恢复到原始的opacity,直到动画结束的时候v-enter-active才被移除,.v-enter-active{transition: opacity 1s;}让3s从0变到对应的opacity的值

(补充:第二帧v-enter被移除、v-enter-to被添加,动画结束v-enter-active、v-enter-to被移除)



        .v-enter{

            opacity:0;

        }

        .v-enter-active{

            transition: opacity 1s;

        }



//上2个是显示的时候渐显的效果

//下2个是隐藏的时候渐隐的效果



        .v-leave-to{

            opacity:0;

        }

        .v-leave-active{

            transition: opacity 1s;

        } 

//【动画渐隐】还没开始的时候v-leave和v-leave-active已经存在,第一帧的时候存在,刚开始是显示状态opacity是1,当动画运行的第二帧的时候v-leave被移除、v-leave-to被添加,opacity变为0,直到动画结束的时候v-leave-active才被移除,.v-leave-active{transition: opacity 1s;}让3s从opacity:1变到对应的opacity的值0

(补充:第二帧v-leave被移除、v-leave-to被添加,动画结束v-leave-active、v-leave-to被移除)



        //合并如下

        */





        .v-enter,.v-leave-to{

            opacity:0;

        }

        .v-enter-active,.v-leave-active{

            transition: opacity 1s;

        }

    </style>

  </head>

  <body>

    

    <div id="root">



        <!-- <transition name="fade"> -->

            <!-- transition写name的话上面style就是name-,不写name也是可以的上面style就是v-  -->

        <transition>

        <div v-if="show">hello world</div>

        <!-- v-if="show"也可以写成v-show="show" -->

        <!-- 除了v-show、v-if,动态组件写在这也可以带动画效果 -->

        </transition>

        <button @click="handleClick">切换</button>

    </div>



    <script>

      var vm = new Vue({

        el: '#root',

        data:{

            show:true

        },

        methods:{

            handleClick:function(){

                this.show=!this.show

            }

        }

      });

    </script>

  </body>

</html>

<!-- Vue动画-Vue中CSS动画原理 -->

<!-- 自动在div元素增加一些class(.v-enter,.v-enter-to……)的一个底层原理,Vue帮助我们实现了CSS的过渡效果,也就是CSS动画效果、过渡动画效果。

实际上,Vue里面的CSS动画是通过在某一时刻自动地往一些标签上增加一些样式来实现的 



Vue实现CSS过渡动画:在想要实现动画的DOM元素外加<transition></transition>,然后再去写对应的样式-->

5_2在Vue中使用animate.css库

1.①

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>在Vue中使用animate.css库</title>

    <script src="../vue.js"></script>

    <style>



        /* @keyframes bounce-in{

            0%{

                transform:scale(0)

            }

            50%{

                transform:scale(1.5)

            }

            100%{

                transform:scale(1)

            }

        }

        .fade-enter-active{

            transform-origin: left center;

            animation:bounce-in 1s;

        }

        .fade-leave-active{

            transform-origin: left center;

            animation:bounce-in 1s reverse;

        } */



/* 可以自定义添加这些自动添加的class的名字,修改如下: */

        @keyframes bounce-in{

            0%{

                transform:scale(0)

            }

            50%{

                transform:scale(1.5)

            }

            100%{

                transform:scale(1)

            }

        }

        .active{

            transform-origin: left center;

            animation:bounce-in 1s;

        }

        .leave{

            transform-origin: left center;

            animation:bounce-in 1s reverse;

        }



    </style>

  </head>

  <body>



    <!-- <div id="root">

        <transition name="fade">

        <div v-show="show">hello world</div>

        </transition>

        <button @click="handleClick">切换</button>

    </div> -->

<!-- 可以自定义添加这些自动添加的class的名字,修改如下: -->

    <div id="root">

        <transition 

         name="fade"

         enter-active-class="active"

         leave-active-class="leave"

        >

        <div v-show="show">hello world</div>

        </transition>

        <button @click="handleClick">切换</button>

    </div>



    <script>

      var vm = new Vue({

        el: '#root',

        data:{

            show:true

        },

        methods:{

            handleClick:function(){

                this.show=!this.show

            }

        }

      });

    </script>

  </body>

</html>



<!-- @keyframes动画是CSS3的动画效果 -->



<!-- 可以自定义添加这些自动添加的class的名字,借助这个功能,我们就可以在Vue项目里使用比较流行的animate.css库了 -->

1.②

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>在Vue中使用animate.css库</title>

    <script src="../vue.js"></script>

    <link rel="stylesheet" type="text/css" href="../animate.css">

  </head>

  <body>



    <div id="root">

        <transition 

         name="fade"

         enter-active-class="animated swing"

         leave-active-class="animated shake"

        >

        <div v-show="show">hello world</div>

        </transition>

        <button @click="handleClick">toggle</button>

    </div>



    <script>

      var vm = new Vue({

        el: '#root',

        data:{

            show:true

        },

        methods:{

            handleClick:function(){

                this.show=!this.show

            }

        }

      });

    </script>

  </body>

</html>



<!-- 可以自定义添加这些自动添加的class的名字,借助这个功能,我们就可以在Vue项目里使用比较流行的animate.css库了 -->



<!-- 在Vue中使用animate.css库 -->

<!-- 使用animate.css库好处:写复杂的CSS动画,我们就不需要自己去写了,直接用库里面提供的动画效果就可以实现 -->

<!-- animate动画库是一个封装 -->



<!-- 使用animate动画库,需要注意:

(1)需要使用自定义class的这种名字形式

(2)自定义class类里面需要包括animated这个具体类,同时根据需求(出场、退场需要实现什么动画效果)来把动画效果的名字写在第二个类的位置上 -->

5_3在Vue中同时使用过渡和动画

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>在Vue中同时使用过渡和动画</title>

    <script src="../vue.js"></script>

    <link rel="stylesheet" type="text/css" href="../animate.css" />

    <style>

      .fade-enter-to,

      .fade-leave-to {

        opacity: 0;

      }

      .fade-enter-active,

      .fade-leave-active {

        transition: opacity 3s;

      }

    </style>

  </head>

  <body>

    <div id="root">

      <transition

        type="transtion"

        name="fade"

        appear

        enter-active-class="animated swing fade-enter-active"

        leave-active-class="animated shake fade-leave-active"

        appear-active-class="animated swing"

      >

        <!-- ①

            animated swing时长是1s,transtion是3s,Vue搞不清楚。【type="transtion"】设置时长以 transtion的3s为准-->



        <!-- ②

            【:duration="2000"】设置自定义播放时长为2000毫秒,即2秒 -->



        <!-- ③

    【:duration="{enter:5000,leave:10000}"】

      入场动画设置为5秒,出场动画设置为10秒。



      点击第一次按钮:控制台显示器可以看到出场div的class"animated shake fade-leave-active fade-leave-to"在10秒后被移除;

      点击第二次按钮:控制台显示器可以看到入场div的class"animated swing fade-enter-active fade-enter-to"在5秒后被移除. 

       -->



        <div v-show="show">hello world</div>

      </transition>

      <button @click="handleClick">toggle</button>

    </div>



    <script>

      var vm = new Vue({

        el: "#root",

        data: {

          show: true,

        },

        methods: {

          handleClick: function () {

            this.show = !this.show;

          },

        },

      });

    </script>

  </body>

</html>

<!-- 5_3在Vue中同时使用过渡和动画

2个知识点:

(1)appear appear-active-class来实现页面初始动画

(2)过渡+动画:①②③↑ -->

5_4Vue中的Js动画与Velocity.js的结合

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的Js动画与Velocity.js的结合</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

        <!-- 入场 -->

      <transition

        name="fade"

        @before-enter="handleBeforeEnter"

        @enter="handleEnter"

        @after-enter="handleAfterEnter"

      >

        <div v-show="show">Hello World</div>

      </transition>





      <!-- 出场同理 -->

      <!-- <transition

        name="fade"

        @before-leave="handleBeforeEnter"

        @leave="handleEnter"

        @after-leave="handleAfterEnter"

      >

        <div v-show="show">Hello World</div>

      </transition> -->







      <button @click="handleClick">toggle</button>

    </div>



    <script>

      var vm = new Vue({

        el: "#root",

        data: {

          show: true,

        },

        methods: {

          handleClick: function () {

            this.show = !this.show;

          },

          handleBeforeEnter: function (el) {

            el.style.color = "red";

          },

          //进入动画之前颜色是红色

          handleEnter: function (el, done) {

            setTimeout(() => {

              el.style.color = "green";

            }, 2000);



            setTimeout(() => {

              done()//记得手动调用done回调函数

            }, 4000);

          },

          //执行动画的时候这个动画效果是2秒之后会变成绿色,4秒动画结束

          handleAfterEnter: function (el) {

            el.style.color = "#000";

          }

          //结束handleAfterEnter把文字颜色变成黑色

        },

      });

    </script>

  </body>

</html>

<!-- Vue之中使用js钩子来实现Vue之中js动画效果(以上是入场js动画) -->



<!--  注意【el】和【done】:

             handleBeforeEnter: function (el) {

            el.style.color = "red";

          },

          //进入动画之前颜色是红色

          handleEnter: function (el, done) {

            setTimeout(() => {

              el.style.color = "green";

            }, 2000);



            setTimeout(() => {

              done()//记得手动调用done回调函数

            }, 4000);

          },

          //执行动画的时候这个动画效果是2秒之后会变成绿色,4秒动画结束

          handleAfterEnter: function (el) {

            el.style.color = "#000";

          } -->





<!-- 有了这些基础就可以去写一些更复杂的动画效果,这个时候引入js动画库Velocity.js动画库见下一个html文件(5_42.html) -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的Js动画与Velocity.js的结合</title>

    <script src="../vue.js"></script>

    <script src="../velocity.js"></script>

  </head>

  <body>

    <div id="root">



      <transition

        name="fade"

        @before-enter="handleBeforeEnter"

        @enter="handleEnter"

        @after-enter="handleAfterEnter"

      >

        <div v-show="show">Hello World</div>

      </transition>



      <button @click="handleClick">toggle</button>

    </div>



    <script>

      var vm = new Vue({

        el: "#root",

        data: {

          show: true,

        },

        methods: {

          handleClick: function () {

            this.show = !this.show;

          },

          handleBeforeEnter: function (el) {

            el.style.opacity = 0;

          },

          handleEnter: function (el, done) {

              Velocity(el,{

                  opacity:1

                  },{

                      duration:1000,

                      complete:done

                      })

          },

          //当Velocity执行完这个动画之后,complete属性对应的内容会被自动地执行,也就是done这个回调函数会被执行,告诉Vue我的动画执行完成了。

          //接下来handleAfterEnter这个函数就会被执行

          handleAfterEnter: function (el) {

            console.log("动画结束")

          }

        }

      });

    </script>

  </body>

</html>

<!-- Velocity.js动画库,通过一些简单的语法可以实现一些酷炫的动画效果 -->

5_5Vue中多个元素或组件的过渡

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中多个元素或组件的过渡</title>

    <script src="../vue.js"></script>

    <!-- 想要实现点击按钮切换Hello World和Bye World时有动画效果→↓[加style] -->

    <style>

        .v-enter,.v-leave-to{

            opacity: 0;

        }

        .v-enter-active,.v-leave-active{

            transition: opacity 1s;

        }

    </style>

  </head>

  <body>

    <div id="root">

        <!-- mode="in-out"显示的元素先显示,隐藏的元素再隐藏

            mode="out-in"隐藏的元素先隐藏,显示的元素再显示 -->

      <transition mode="out-in">

        <div v-if="show" key="hello">Hello World</div>

        <div v-else key="bye">Bye World</div>

      </transition>

<!-- Vue复用DOM导致没有动画效果显示,解决办法:加key值,这样当div元素隐藏或者显示的时候上下就不会复用了 -->



      <button @click="handleClick">toggle</button>

    </div>



    <script>

      var vm = new Vue({

        el: "#root",

        data: {

          show: true,

        },

        methods: {

          handleClick: function () {

            this.show = !this.show;

          }

        }

      });

    </script>

  </body>

</html>

<!-- 多个元素的过渡动画实现 -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中多个元素或组件的过渡</title>

    <script src="../vue.js"></script>

    <!-- 想要实现点击按钮切换Hello World和Bye World时有动画效果→↓[加style] -->

    <style>

      .v-enter,

      .v-leave-to {

        opacity: 0;

      }

      .v-enter-active,

      .v-leave-active {

        transition: opacity 1s;

      }

    </style>

  </head>

  <body>

    <div id="root">



      <transition mode="out-in">

        <child v-if="show"></child>

        <child-one v-else></child-one>

      </transition>



      <button @click="handleClick">toggle</button>

    </div>



    <script>

      Vue.component("child", {

        template: "<div>child</div>",

      });



      Vue.component("child-one", {

        template: "<div>child-one</div>",

      });



      var vm = new Vue({

        el: "#root",

        data: {

          show: true,

        },

        methods: {

          handleClick: function () {

            this.show = !this.show;

          },

        },

      });

    </script>

  </body>

</html>

<!-- 多个组件的过渡动画实现--

    多个组件的切换的时候transition效果以上代码可以实现,

    换一种方式--用到动态组件实现以上功能见下一个html文件(5_53.html) -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中多个元素或组件的过渡</title>

    <script src="../vue.js"></script>

    <!-- 想要实现点击按钮切换Hello World和Bye World时有动画效果→↓[加style] -->

    <style>

      .v-enter,

      .v-leave-to {

        opacity: 0;

      }

      .v-enter-active,

      .v-leave-active {

        transition: opacity 1s;

      }

    </style>

  </head>

  <body>

    <div id="root">



      <transition mode="out-in">

        <component :is="type"></component>

        <!-- 用is来控制展示哪一个组件 -->

      </transition>



      <button @click="handleClick">toggle</button>

    </div>



    <script>

      Vue.component('child', {

        template: '<div>child</div>',

      })



      Vue.component('child-one', {

        template: '<div>child-one</div>',

      })



      var vm = new Vue({

        el: "#root",

        data: {

          type: 'child'//type初始值是type

        },

        methods: {

          handleClick: function () {

            this.type = this.type==='child'?'child-one':'child';

          },

        },

      });

    </script>

  </body>

</html>

<!-- 多个组件的过渡动画实现--

    用【动态组件】实现 -->

5_6Vue中的列表过渡

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的列表过渡</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

        <div v-for="(item,index) of list" :key="item.id">

            {{item.title}}

        </div>

        <button @click="handleBtnClick">Add</button>

    </div>



    <script>

        var count=0

      var vm = new Vue({

        el: "#root",

        data:{

            list:[]

        },

        methods:{

            handleBtnClick:function(){

                this.list.push({

                    id:count++,

                    title:'hello world'

                })

            }

        }

      });

    </script>

  </body>

</html>

<!-- 实现Vue中的列表过渡动画见下一个html文件(5_62.html) -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的列表过渡</title>

    <script src="../vue.js"></script>

    <style>

      .v-enter,

      .v-leave-to {

        opacity: 0;

      }

      .v-enter-active,

      .v-leave-active {

        transition: opacity 1s;

      }

    </style>

  </head>

  <body>

    <div id="root">

      <transition-group>

        <div v-for="(item,index) of list" :key="item.id">

          {{item.title}}

        </div>

      </transition-group>

      <button @click="handleBtnClick">Add</button>

    </div>



<!-- 相当于:

<transition>

    <div>hello world</div>

</transition>

<transition>

    <div>hello world</div>

</transition>

<transition>

    <div>hello world</div>

</transition>

<transition>

    <div>hello world</div>

</transition> -->



    <script>

      var count = 0;

      var vm = new Vue({

        el: "#root",

        data: {

          list: [],

        },

        methods: {

          handleBtnClick: function () {

            this.list.push({

              id: count++,

              title: "hello world",

            });

          },

        },

      });

    </script>

  </body>

</html>

<!-- Vue中的列表过渡 -->

5_7Vue中的动画封装

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的动画封装</title>

    <script src="../vue.js"></script>

    <style>

        .v-enter,.v-leave-to{

            opacity: 0;

        }

        .v-enter-active,.v-leave-active{

            transition:opacity 1s;

        }

    </style>

  </head>

  <body>

    <div id="root">

      <fade :show="show">

        <div>hello world</div>

      </fade>



      <fade :show="show">

        <h1>hello world</h1>

      </fade>



      <button @click="handleBtnClick">toogle</button>

    </div>



    <script>

      Vue.component("fade", {

        props: ["show"],

        template: `

    <transition>

    <slot v-if="show"></slot>

    </transition>

    `,

      });

      var vm = new Vue({

        el: "#root",

        data: {

          show: false,

        },

        methods: {

          handleBtnClick: function () {

            this.show = !this.show;

          },

        },

      });

    </script>

  </body>

</html>

<!-- CSS动画被封装了起来,2个hello world都有渐隐渐显的效果 -->

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title>Vue中的动画封装</title>

    <script src="../vue.js"></script>

  </head>

  <body>

    <div id="root">

      <fade :show="show">

        <div>hello world</div>

      </fade>



      <fade :show="show">

        <h1>hello world</h1>

      </fade>



      <button @click="handleBtnClick">toogle</button>

    </div>



    <script>

      Vue.component("fade", {

        props: ["show"],

        template: `

      <transition @before-enter="handleBeforeEnter"

                  @enter="handleEnter">

      <slot v-if="show"></slot>

      </transition>

      `,

        methods: {

          handleBeforeEnter: function (el) {

            el.style.color = "red";

          },

          handleEnter: function (el, done) {

            setTimeout(() => {

              el.style.color = "green";

              done();

            }, 2000);

          },

        },

      });

      var vm = new Vue({

        el: "#root",

        data: {

          show: false,

        },

        methods: {

          handleBtnClick: function () {

            this.show = !this.show;

          },

        },

      });

    </script>

  </body>

</html>

<!-- Vue中的动画封装 -->

<!-- 对比上一个html文件,这个把style里面的内容也封装了起来,所有的动画都写在fade组件里面,不用在全局去写一些style样式了,是比较推荐的动画封装 -->