Vue入门详解

一,VUE的核心

1.数据驱动(mvvm模型,只要改变model的数据,视图层就会自动更新)

2.视图组件: 把整一个网页的拆分成一个个区块,每个区块我们可以看作成一个组件。网页由多个组件拼接或者嵌套组成。

二,使用vue

1.引入vue之后就可以进行下面的步骤

2.创建语法(创建 ,设置数据,挂载,渲染)

var vm = new Vue({})//参数是一个对象
 

三、定义一个vue实例的4个常用选项

1.过滤器 filter属性:

例如我们从后台取出来的数据都是带有小数位的,但是需求上面要求的是只展示整数部分,这个时候我们就可以用过滤器属性了。我们先创建一个实例,数据中的格式都是带有小数点的,此时我们创建filters属性(记住此属性的值是一个对象,所以":"之后要带上大括号“{}”,在filters里面我们写一个转换函数,这个函数的功能就是将传参转换为整数后返回,此处用的是es6的语法),写好函数后要怎么使用呢?我们在div里面,将参数用管道符号"|"传给toInt函数,这样就可以了!

<div id="app6">

    数字1:{{num1 | toInt}}

    数字2:{{num2 | toInt}}

    数字3:{{num3 | toInt}}

</div>



let app6 = new Vue({

    el:'#app6',

    data:{

        num1:123.4,

        num2:520.1314,

        num3:1314.520

    },

    filters:{

        toInt(value){

                return parseInt(value);

             }

    }

});
4.计算属性computed

 

有时候,我们拿到一些数据,需要经过处理计算后得到的结果,才是我们要展示的内容。

比如:我们有三个数,但是需要展示的是三个数字之和。这种情况,就适合用我们的计算属性computed。(可以直接调用计算属性里面的值。)

let app6 = new Vue({

    el:'#app6',

    data:{

        num1:123.4,

        num2:520.1314,

        num3:1314.520

    },

    filters:{

        toInt(value){

                return parseInt(value);

             }

    },

    computed:{

        sum(){

            return parseInt(this.num1+this.num2+this.num3);

        }

    }

});
计算属性computed的定义语法和过滤器filters类似,但是用法不一,如下:

总和是{{sum}}

我们提供的函数将用作属性app6.sum 的 getter 函数:

计算属性拥有getter和setter两个属性,也就是我们可以设置这两个属性,例如

computed: {

  fullName: {

    // getter

    get: function () {

      return this.firstName + ' ' + this.lastName

    },

    // setter

    set: function (newValue) {

      var names = newValue.split(' ')

      this.firstName = names[0]

      this.lastName = names[names.length - 1]

    }

  }

}

那么每次运行fullname的时候,就是使用getter,返回一个值,而每次执行fullname = ""的时候,就会执行set里面的函数,将firstname和lastname都进行改变。

 

需要注意的是,sum的值是依赖data中的数据num1,num2,num3的,一旦它们发生了变化,sum的值也会自动更新

 

5.methods  方法

顾名思义,在methods中,我们可以定义一些方法,供组件使用。

比如,我们定义一个数据a,当用户点击按钮的时候,a的值加1。这种情况,我们可以利用methods来实现。

 

定义一个plus( )的方法在methods中,下面我们把plus( ) 绑定在按钮的点击事件上

let vm = new Vue({

    //挂载元素

  el:'#app',

    //实例vm的数据

  data:{

         a:0

    },

    //方法

  methods:{

        plus(){

            return this.a++;

        }

    }

});

<div id="app">

    {{ a }}

    <button v-on:click="plus">加1</button>

  </div>
  

 

1. 计算属性computed和方法methods都能用于计算,说说两者的区别?

答: 假设我们计算一个值sum,它是经过a和b相加得到的结果。

      如果我们使用计算属性的方式来实现得到sum,由于计算属性computed是基于它的依赖进行缓存的,也就是sum的值只有在a或者b的值发生变化的时候才会重新计算求值。这就意味着,倘若a和b的值不发生改变,即使重新渲染或者多次访问计算属性中的sum,都无需重新计算,节省运算开销。

        反观,如果我们用methods方法来定义一个求和函数sum( )来计算a和b的求和,如果多个地方需要渲染a和b的和,我们则需要多此调用sum( )方法,这样的后果就是多次重复执行函数,造成不必要的运算开销。

 

 

6.watch 观察

watch选项是Vue提供的用于检测指定的数据发生改变的api,也就是说,当这个数据发生变化的时候会触发对应的函数。

上面点击按钮a的值加1的例子,不就是数据发生变化了吗?我们就用watch选项来监听数字a是否发生了变化,如果了监听到了变化,我们就在控制台输入以下a的最新值。

在上个例子的代码基础上,我们加上watch部分的代码

let vm = new Vue({

    //挂载元素

  el:'#app',

    //实例vm的数据

  data:{

         a:0

    },

    //方法

  methods:{

        plus(){

            return this.a++;

        }

    },

    //观察

  watch:{

        a(){

          console.log(`有变化了,最新值:`);

          console.log(this.a);

        }

    }

});
最后一部分watch就是我们新加的代码,a( ) 表示我们要观察监听的就是数据a,

 

四.vue实例的生命周期:


不要在选项属性或者回调函数上面使用箭头函数,因为箭头函数是和父级上下文绑定在一起的。

 

1. beforeCreate(还没创建实例)

此阶段为实例初始化之后,此时的数据观察和事件配置都没好准备好。

我们试着console一下实例的数据data和挂载元素el,代码如下:

  

<div id="app7">{{name}}</div>

  <script>

    let app7 = new Vue({

      el:"#app7",

        data:{

         name:"krys"

      },

      beforeCreate(){

         console.log('即将创建');

         console.log(this.$data);

         console.log(this.$el);

      }

    });

</script>

 

得到的结果是:

 

此时的实例中的data和el还是undefined,不可用的。

 

2. created(创建实例)

beforeCreate之后紧接着的钩子就是创建完毕created,我们同样打印一下数据data和挂载元素el,看会得到什么?

在上一段代码的基础上,加上下面这段代码:

created(){

    console.log('创建完毕');

    console.log(this.$data);

    console.log(this.$el);

}
我们看到打印的结果:

 

此时,我们能读取到数据data的值,但是DOM还没生成,所以属性el还不存在,输出$data为一个Object对象,而$el的值为undefined。

 

3. beforeMount(生成dom)

上一个阶段我们知道DOM还没生成,属性el还为undefined,那么,此阶段为即将挂载,我们打印一下此时的$el是什么?

增加一下代码:

beforeMount(){

    console.log('即将挂载');

    console.log(this.$el);

}
我们看到打印结果:

 

此时的$el不再是undefined,而是成功关联到我们指定的dom节点<div id=”app”></div>,但此时{{ name }}还没有被成功地渲染成我们data中的数据。没事,我们接着往下看。

4. mounted(将实例与dom相连)

mounted也就是挂载完毕阶段,到了这个阶段,数据就会被成功渲染出来,我们编写mounted的钩子,打印$el 看看:

 

mounted(){

    console.log('挂载完毕');

    console.log(this.$el);

}

打印结果

 

 

如我们所愿,此时打印属性el,我们看到{{ name }}已经成功渲染成我们data.name的值:“krys”。

5. beforeUpdate(实例更新前)

我们知道,当修改vue实例的data时,vue就会自动帮我们更新渲染视图,在这个过程中,vue提供了beforeUpdate的钩子给我们,在检测到我们要修改数据的时候,更新渲染视图之前就会触发钩子beforeUpdate。

html片段代码我们加上ref属性,用于获取DOM元素。

<div ref="app7" id="app7">

    {{name}}

</div>

Vue实例代码加上beforeUpdate钩子代码:

beforeUpdate(){

  console.log('=即将更新渲染=');

  let name = this.$refs.app7.innerHTML;

  console.log('name:'+name);

},
我们试一下,在控制台修改一下实例的数据name,在更新渲染之前,我们打印视图中文本innerHTML的内容会是多少:

 

 

我们在控制台把app.name的值从原来的 “krys” 修改成 “斑马”,在更新视图之前beforeUpdate打印视图上的值,结果依然为原来的值:“krys”,表明在此阶段,视图并未重新渲染更新。

6. updated(实例更新完成之后)

此阶段为更新渲染视图之后,此时再读取视图上的内容,已经是最新的内容,接着上面的案例,我们添加钩子updated的代码,如下:

updated(){

  console.log('==更新成功==');

  let name = this.$refs.app7.innerHTML;

  console.log('name:'+name);

}
结果如下:

 

大家注意两个不同阶段打印的name的值是不一样,updated阶段打印出来的name已经是最新的值:“斑马”,说明此刻视图已经更新了。

7. beforeDestroy

调用实例的destroy( )方法可以销毁当前的组件,在销毁前,会触发beforeDestroy钩子。

8. destroyed

成功销毁之后,会触发destroyed钩子,此时该实例与其他实例的关联已经被清除,它与视图之间也被解绑。

案例:我们通过在销毁前通过控制台修改实例的name,和销毁之后再次修改,看看情况。

beforeDestroy(){

   console.log('销毁之前');

},

destroyed(){

   console.log('销毁成功');

}
效果如下图:

 

 

销毁之前,修改name的值,可以成功修改视图显示的内容为:“更新视图”,一旦效用实例的$destroy( )方法销毁之后,实例与视图的关系解绑,再修改name的值,已于事无补,视图再也不会更新了,说明实例成功被销毁了。

 

9. actived

keep-alive组件被激活的时候调用。

10. deactivated

keep-alive 组件停用时调用。

关于keep-alive组件的激活和停用

 

以后最为常用的钩子是:created 成功创建。

 

 五.在html中绑定数据

1.Mustache语法:{{}}的写法,在里面写入需要渲染的数据

<div id ="app7">{{name}}</div>
let app7 = new Vue({

    el:"#app7",

    data:{

        name:"krys"

    }

}
 

2.绑定纯html

如果上面的例子中,name的值是一些html语句,如果单纯的是像上面这样写的话,会原样输出,不会转化为html语句,例如

<div id="app8">

    {{name}}

</div>

<script>

    let app8  = new Vue({

        el:"#app8",

        data:{

            name:"<strong>krys</strong>"

        }

    })

</script>


并不能得到我们想要的效果,这时候需要用到vue提供的v-html指令,

<div id="app8" v-html="name">

    {{name}}

</div>

<script>

    let app8  = new Vue({

        el:"#app8",

        data:{

            name:"<strong>krys</strong>"

        }

    })

</script>
 

 

3.绑定属性:attr或者v-bind:attr,其中attr是属性名, 需要注意的是:当渲染的属性值是布尔值的时候(true和false),效果就不一样了,并不是简单地将true或者false渲染出来,而是当值为false的时候,属性会被移除。

<div id="app9">

   <a v-bind:href="link" >baidu</a>

</div>

let app9 = new Vue({

    'el':"#app9",

    data:{

        link:"https://www.baidu.com"

    }

})

4.支持javascript表达式

值得注意的是,只能包含单个表达式,多个表达式组成的不会生效!

上面讲到的都是将数据简单地绑定在视图上,但事实上,vue还支持我们对数据进行简单的运算:javascript表达式支持。

<div id="app">{{ num+3 }}</div>

<script>

let app = new Vue({

    el:"#app",

    data:{

        num:2

    }

});

</script>

<div id="app">

  <a :href="'http://'+host">hello官网</a>

</div>

<script>

let app = new Vue({

    el:"#app",

    data:{

        host:'hello.com'

    }

});

</script>

六,必须要掌握的指令

1.v-text指令

v-text指令用于更新标签包含的文本,他的作用跟双大括号{{}}一样,

<div id="app">

    <p v-text="msg"></p>

</div>

<script>

    let app = new Vue({

        el:"#app",

        data:{

            msg:"hello,vue"

        }

    })

</script>


2.v-html指令(执行html)

这个指令帮助我们绑定一些包含html代码的数据在视图上。

<div id="app">

    <p v-html="msg"></p>

</div>

<script>

    let app = new Vue({

        el:"#app",

        data:{

            msg:"<b>hello,vue</b>"

        }

    })

</script>


 

3.v-show指令

控制元素的css中display属性,v-show指令的取值为true/false,分别对应着显示/隐藏。

<div id="app">

    <p v-show="show1">我是true</p>

    <p v-show="show2">我是false</p>

</div>

<script>

    let app = new Vue({

        el:"#app",

        data:{

           show1:true,

            show2:false

        }

    })

</script>


4.v-if(其实就相当于if)

v-if指令的取值也是true或者false,它控制元素是否需要被渲染出来,设置为true的<p>标签,成功渲染出来,而设置为false的<p>标签,直接被一行注释代替了,并没有被解析渲染出来。

那么如何区别v-show和v-if这两个指令呢?就是一个会被渲染出来,一个不会。记住一个很重要的点:如果需要频繁切换显示/隐藏的,就用 v-show ;如果运行后不太可能切换显示/隐藏的,就用 v-if 。

<div id="app">

    <p v-if="if_1">我是true</p>

    <p v-if="if_2">我是true</p>

</div>

<script>

    let app = new Vue({

        el:"#app",

        data:{

           if_1:true,

            if_2:false

        }

    })

</script>
 

 

5.v-else指令(相当于else)

 

1) if和else指令,在一般的变成语言都是结对出现,在vue里也不例外,它没有对应的值,但是要求前一个兄弟节点必须使用v-if指令。(没有if哪来的else),如果v-if的值为true那么else里面的东西将不会渲染出来

<div id="app">

    <p v-if="if_1">我是if</p>

    <p v-else="">我是else</p>

</div>

<script>

    let app = new Vue({

        el:"#app",

        data:{

           if_1:true,

        }

    })

</script>



<script>

    let app = new Vue({

        el:"#app",

        data:{

           if_1:false,

        }

    })

</script>

 


 

 

3)v-else-if

<div v-if="type === 'A'">

  A

</div>

<div v-else-if="type === 'B'">

  B

</div>

<div v-else-if="type === 'C'">

  C

</div>

<div v-else>

  Not A/B/C

</div>
v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

 

4)使用key来管理可复用的元素

Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:

<template v-if="loginType === 'username'">

  <label>Username</label>

  <input placeholder="Enter your username">

</template>

<template v-else>

  <label>Email</label>

  <input placeholder="Enter your email address">

</template>





new Vue({

    el: '#app',

    data: {

        loginType:"username"

    },

    methods:{

        change:function () {

            this.loginType == "username" ? this.loginType = "email":this.loginType = "username";

        }

    }

});

那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder。

 

这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key 属性即可。

<template v-if="loginType === 'username'">

  <label>Username</label>

  <input placeholder="Enter your username" key="username-input">

</template>

<template v-else>

  <label>Email</label>

  <input placeholder="Enter your email address" key="email-input">

</template>





new Vue({

    el: '#app',

    data: {

        loginType:"username"

    },

    methods:{

        change:function () {

            this.loginType == "username" ? this.loginType = "email":this.loginType = "username";

        }

    }

});

现在,每次切换时,输入框都将被重新渲染。

6.v-for指令

v-for指令用来进行循环,不但可以迭代数组,还可以迭代对象和整数,下面例子中,index是索引,item是值(有先后顺序,第一个是值,第二个是索引)。可以看到生成了4个div

<div id="app">

   <div v-for="(item,index) in list">{{index}}.我们的成员有:{{item}}</div>

</div>

<script>

    let app = new Vue({

        el:"#app",

        data:{

           list:['krys','zebra','tom','jackson']

        }

    })

</script>


 

用for in或者for of遍历对象的时候,第一个参数是值,第二个参数是键名,第三个参数是索引。在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。

<ul id="v-for-object" class="demo">

    <li v-for="(value,key) of object">

       {{key}}-- {{value}}

    </li>

</ul>





new Vue({

    el:"#v-for-object",

    data:{

        object:{

            firstName:"liang",

            lastName:"krys",

            fullName:"krys liang",

            age:23

        }

    }

});


尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。因为它是 Vue 识别节点的一个通用机制。

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似 Vue 1.x 的 track-by="$index" 。

这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的唯一 id。这个特殊的属性相当于 Vue 1.x 的 track-by ,但它的工作方式类似于一个属性,所以你需要用 v-bind 来绑定动态值 (在这里使用简写):

<div v-for="item in items" :key="item.id">

  <!-- 内容 -->

</div>

 

 

当对数组进行下面两个操作的时候,数组不会进行响应式的变化,也就是说,即使进行了下面的两个操作,数据也不会重新渲染

1)利用索引直接设置一个值

2)修改数组的长度

 

var vm = new Vue({

  data: {

    items: ['a', 'b', 'c']

  }

})

vm.items[1] = 'x' // 不是响应性的

vm.items.length = 2 // 不是响应性的

 

为了解决第一类问题,改用下面两个方法来实现同样的效果

Vue.set(vm.items, indexOfItem, newValue)

 

vm.items.splice(indexOfItem, 1, newValue)

 

vm.$set(vm.items, indexOfItem, newValue)

 

 

为了解决第二类问题,可以改用下面的方法

vm.items.splice(newLength)

 

 

还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:

var vm = new Vue({

  data: {

    a: 1

  }

})

// `vm.a` 现在是响应式的

 

vm.b = 2

// `vm.b` 不是响应式的

对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性。例如,对于:

var vm = new Vue({

  data: {

    userProfile: {

      name: 'Anika'

    }

  }

})

你可以添加一个新的 age 属性到嵌套的 userProfile 对象:

Vue.set(vm.userProfile, 'age', 27)

你还可以使用 vm.$set 实例方法,它只是全局 Vue.set 的别名:

vm.$set(vm.userProfile, 'age', 27)

有时你可能需要为已有对象赋予多个新属性,比如使用 Object.assign() 或 _.extend()。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性

vm.userProfile = Object.assign({}, vm.userProfile, {

  age: 27,

  favoriteColor: 'Vue Green'

})

 

 

当v-for和v-if处于同一个节点的时候,v-for的优先级比v-if要高,这就是说v-if将分别运行于每个v-for循环中。

<li v-for="todo in todos" v-if="!todo.isComplete">

  {{ todo }}

</li>

 

当在自定义组件中使用 v-for 时,key 现在是必须的。然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要用 props 

<my-component

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

  v-bind:item="item"

  v-bind:index="index"

  v-bind:key="item.id">

 

</my-component>

 

 

 

 

7.v-bind指令

v-bind指令用于动态绑定DOM元素的属性(例如href,src等),其中:href等价于v-bind:href

<div id="app">

    <a :href="link">百度官网</a>

</div>

<script>

    let app = new Vue({

        el:"#app",

        data:{

           link:"https://www.baidu.com"

        }

    })

</script>


 

8.v-on指令

 

v-on指令相当于绑定事件的监听器,绑定的事件触发了,可以指定事件的处理函数。

<div id="app">

   <button v-on:click="say('krys')">调用say函数</button>

</div>

<script>

    let app = new Vue({

        el:"#app",

        methods:{

            say(name){

                console.log("hello"+name);

            }

        }

    })

</script>


在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

 

<form v-on:submit.prevent="onSubmit">...</form>

.stop ==stopPropagation->阻止事件继续传播

.prevent == preventDefault ->去除默认行为(form提交不再重载页面)

.capture ->添加事件监听器时使用事件捕获模式,也就是元素自身出发的事件先在此处理,然后才交给内部元素进行处理

.self ->只在event.target是当前元素自身时才触发处理函数

.once->点击事件只会触发一次

.passive->passive是不拦截默认事件

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符。

<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->

<!-- 而不会等待 `onScroll` 完成  -->

<!-- 这其中包含 `event.preventDefault()` 的情况 -->

<div v-on:scroll.passive="onScroll">...</div>

这个 .passive 修饰符尤其能够提升移动端的性能。

不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。

 

按键修饰符

 

在监听键盘事件的时候,经常需要检查常见的键值。

<input v-on:keyup.13="submit"><!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` -->

 

 

上面的keycode是按键的编码,等同于下面

 

<!-- 同上 -->

<input v-on:keyup.enter="submit">

 

<!-- 缩写语法 -->

<input @keyup.enter="submit">

 

所有的按键别名

.enter

.tab

.delete (捕获“删除”和“退格”键)

.esc

.space

.up

.down

.left

.right

 

可以通过全局 config.keyCodes 对象自定义按键修饰符别名:

// 可以使用 `v-on:keyup.f1`

Vue.config.keyCodes.f1 = 112

 

9、v-model指令(在input、textarea、select这三个元素上创建双向数据绑定。)

v-model会忽略所有表单元素的value、checked、selected特性的初始值而总是将vue实例的数据作为数据来源。应该在data中声明初始值,

这个指令是非常重要且非常常用,一般用在表单输入,它帮助我们轻易的实现表单控件和数据的双向绑定,相对于之前的手动更新DOM,简直就是我们的天使。要注意的是v-model中的值,data中变量的名字,p标签中的{{}}里面的值,三者要一致。因为就是iniput输入的值被绑定到了data中,然后输出到p中。

<div id="app">

   <input v-model="msg" type="text">

    <p>上面输入的值是:{{msg}}</p>

</div>

<script>

    let app = new Vue({

        el:"#app",

       data:{

            msg:""

       }

    })

</script>
 

 

10.v-once指令

这个指令的特点是只渲染一次,后面元素中的数据再更新变化,都不会重新渲染。

<div id="app">

    <input v-model="msg"  type="text">

    <p v-once>你输入:{{ msg }}</p>

</div>

<script>

    let app = new Vue({

        el:"#app",

        data:{

            msg:'hello,我是krys啊哈哈哈哈'

        },

        watch:{

          msg(){

              console.log(this.msg);

          }

        }

    });

</script>


 

select元素中,如果表达式的初始值没有匹配任何选项(也就是没有指定默认值),select元素将会被渲染为未被选中的状态。这个状况下面再ios就会引发一些bug。所以,在option中提空一个空的禁用的选项。

<div id="example-5">

  <select v-model="selected">

    <option disabled value="">请选择</option>

    <option>A</option>

    <option>B</option>

    <option>C</option>

  </select>

  <span>Selected: {{ selected }}</span>

</div>



new Vue({

  el: '#example-5',

  data: {

    selected: ''

  }

})
多选的时候,象下面那样绑定到一个数组

<div id="example-6">

  <select v-model="selected" multiple style="width: 50px;">

    <option>A</option>

    <option>B</option>

    <option>C</option>

  </select>

  



  <span>Selected: {{ selected }}</span>

</div>

new Vue({

  el: '#example-6',

  data: {

    selected: []

  }

})



<select v-model="selected">

  <option v-for="option in options" v-bind:value="option.value">

    {{ option.text }}

  </option>

</select>

<span>Selected: {{ selected }}</span>

new Vue({

  el: '...',

  data: {

    selected: 'A',

    options: [

      { text: 'One', value: 'A' },

      { text: 'Two', value: 'B' },

      { text: 'Three', value: 'C' }

    ]

  }

})

<!-- 当选中时,`picked` 为字符串 "a" -->

<input type="radio" v-model="picked" value="a">

 

<!-- `toggle` 为 true 或 false -->

<input type="checkbox" v-model="toggle">

 

<!-- 当选中第一个选项时,`selected` 为字符串 "abc" -->

<select v-model="selected">

    <option value="abc">ABC</option>

</select>

 

 

data: {

    picked:this.value,

    toggle:"false",

    selected:this._value

},

 

 

 

修饰符

1).lazy,只有当值改变的时候才进行同步

<!-- 在“change”时而非“input”时更新 -->

<input v-model.lazy="msg" >

2).number

将用户的输入值自动转换为数值类型

<input v-model.number="age" type="number">

3).trim

自动过滤用户输入的首尾空白字符,可以给v-model添加.trim修饰符

<input v-model.trim="msg">

 

 

 

 

 

 

七.vue中的组件

1)一个组件的data选项必须是一个函数,所有的数据放在return里面。只有这样,每个实例才可以维护一份被返回对象的独立的拷贝。

data: function () {

  return {

    count: 0

  }

}

 

2)注册组件

全局注册:Vue.component.这样全局注册之后,可以用在任何新创建的vue实例中

局部注册:先声明组件,然后再实例中的components中使用组件。

局部注册中可以通过一个不同的JavaScript对象来定义组件

var ComponentA = { /* ... */ }

var ComponentB = { /* ... */ }

var ComponentC = { /* ... */ }

 

然后再components选项中定义想要使用的组件

new Vue({

  el: '#app',

  components: {

    'component-a': ComponentA,

    'component-b': ComponentB

  }

})
对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。

注意局部注册的组件在其子组件中不可用。

 

例如,如果你希望 ComponentA 在 ComponentB 中可用,则你需要这样写:

var ComponentA = { /* ... */ }



var ComponentB = {

  components: {

    'component-a': ComponentA

  },

  // ...

}
 

在模块系统中局部注册

在这些情况下,我们推荐创建一个 components 目录,并将每个组件放置在其各自的文件中。

然后你需要在局部注册之前导入每个你想使用的组件。例如,在一个假设的 ComponentB.js 或 ComponentB.vue 文件中:

import ComponentA from './ComponentA'

import ComponentC from './ComponentC'



export default {

  components: {

    ComponentA,

    ComponentC

  },

  // ...

}
这样就可以在conponentB中的模板使用componentA和c了。

 

 

 

在模块中,基础组件的自动化全局注册

1)什么是基础组件

许多组件只是包裹了一个输入框或者按钮这类的元素,是相对通用的,把它们称之为基础组件,它们会在各个组件中被频繁的使用。

这样就会导致很多包含基础组件的长列表

import BaseButton from './BaseButton.vue'

import BaseIcon from './BaseIcon.vue'

import BaseInput from './BaseInput.vue'



export default {

  components: {

    BaseButton,

    BaseIcon,

    BaseInput

  }

}

所以在webpack中,使用require.context只在全局注册这些通用的基础组件。

在入口文件中(src/main.js中全局导入基础组件的实例代码)

import Vue from 'vue'

import upperFirst from 'lodash/upperFirst'

import camelCase from 'lodash/camelCase'



const requireComponent = require.context(

  // 其组件目录的相对路径

  './components',

  // 是否查询其子目录

  false,

  // 匹配基础组件文件名的正则表达式

  /Base[A-Z]\w+\.(vue|js)$/

)



requireComponent.keys().forEach(fileName => {

  // 获取组件配置

  const componentConfig = requireComponent(fileName)



  // 获取组件的 PascalCase 命名

  const componentName = upperFirst(

    camelCase(

      // 剥去文件名开头的 `./` 和结尾的扩展名

      fileName.replace(/^\.\/(.*)\.\w+$/, '$1')

    )

  )



  // 全局注册组件

  Vue.component(

    componentName,

    // 如果这个组件选项是通过 `export default` 导出的,

    // 那么就会优先使用 `.default`,

    // 否则回退到使用模块的根。

    componentConfig.default || componentConfig

  )

})
记住全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生。

 

3)通过props向子组件传递数据

HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

Vue.component('blog-post', {

  // 在 JavaScript 中是 camelCase 的

  props: ['postTitle'],

  template: '<h3>{{ postTitle }}</h3>'

})

<!-- 在 HTML 中是 kebab-case 的 -->

<blog-post post-title="hello!"></blog-post>
如果你使用字符串模板,这个限制就不存在。

 

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样

Vue.component('blog-post', {

  props: ['title'],

  template: '<h3>{{ title }}</h3>'

})
 

一个 prop 被注册之后,你就可以像这样把数据作为一个自定义特性传递进来:

<blog-post title="My journey with Vue"></blog-post>

<blog-post title="Blogging with Vue"></blog-post>

<blog-post title="Why Vue is so fun"></blog-post>

 

此外还可以定义传进来的prop数据的类型

props: {

  title: String,

  likes: Number,

  isPublished: Boolean,

  commentIds: Array,

  author: Object

}

 

当子组件需要对prop传入的数据进行处理的时候,最好要有一个本地的数据来进行接收,而不要直接改变prop传进来的数据。

我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。

为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:

Vue.component('my-component', {

  props: {

    // 基础的类型检查 (`null` 匹配任何类型)

    propA: Number,

    // 多个可能的类型

    propB: [String, Number],

    // 必填的字符串

    propC: {

      type: String,

      required: true

    },

    // 带有默认值的数字

    propD: {

      type: Number,

      default: 100

    },

    // 带有默认值的对象

    propE: {

      type: Object,

      // 对象或数组默认值必须从一个工厂函数获取

      default: function () {

        return { message: 'hello' }

      }

    },

    // 自定义验证函数

    propF: {

      validator: function (value) {

        // 这个值必须匹配下列字符串中的一个

        return ['success', 'warning', 'danger'].indexOf(value) !== -1

      }

    }

  }

})

当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 在 default 或 validator 函数中是不可用的(这些是在实例创建之后才可以使用)。

非prop的特性

一个非prop特性是值传向一个组件,但是该组件并没有相应prop定义的特性。但是组件可以接收这样的特性,并且添加到这个组件的跟元素上。

替换/合并已有的特性

如果组件内部已经设置好的属性,再从组件的父级传入进来,就会替换掉组件内部设置好的值。但是,class和style这两个特性会只能一些,会把组件内部和外部的值合并起来,得到最终的值。

禁用特性继承(就是不要让组件的根元素,继承父级的所有属性,将父元素的元素拆开来,赋予给不同的组件元素)

 

<base-input

        v-model="username"

        class="username-input"

        placeholder="Enter your username"

        label = "123"

></base-input>

 

Vue.component('base-input', {

      inheritAttrs: false,

      props: ['label', 'value'],

      template: `

  <label>

    {{ label }}

    <input

      v-bind="$attrs"

      v-bind:value="value"

      v-on:input="$emit('input', $event.target.value)"

    >

  </label>

`

  })

 

  new Vue({

      el: '#todo-list-example',

      data: {

          username:""

      }

  })

 

可以看到父元素的label属性赋予了组件中的label标签,而其他的属性李如玉placeholder、class等则绑定在了$attrs上面,赋予给了input元素

4)通过事件向父级组件发送消息

在下面的例子中blog-post是父组件,父组件中的postFontSize是用来控制博文的字号

new Vue({

  el: '#blog-posts-events-demo',

  data: {

    posts: [/* ... */],

    postFontSize: 1

  }

})

 

然后在模板中添加一个按钮用来放大字号(利用自定义事件,将enlarge-text事件传给父组件)

Vue.component('blog-post', {

  props: ['post'],

  template: `

    <div class="blog-post">

      <h3>{{ post.title }}</h3>

      <button v-on:click="$emit('enlarge-text')">

        Enlarge text

      </button>

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

    </div>

  `

})

 

然后再父组件中的模板上面监听这个事件

<div id="blog-posts-events-demo">

  <div :style="{ fontSize: postFontSize + 'em' }">

    <blog-post

      v-for="post in posts"

      v-bind:key="post.id"

      v-bind:post="post"

        v-on:enlarge-text="postFontSize += 0.1"

    ></blog-post>

  </div>

</div>

 

此外,还可以通过这个自定义的事件给父组件传数据

在$emit的第二个参数中填写的是这个数据

例如在上面的例子中,我们由子组件来决定放大多少倍,在模板中的button改成下面

<button v-on:click="$emit('enlarge-text', 0.1)">

  Enlarge text

</button>

 

可以看到,这里的参树为0.1,也就是每次点击都放大0.1em

 

然后在父级组件监听这个事件的时候,访问这个数据

<blog-post

  ...

  v-on:enlarge-text="postFontSize += $event"

></blog-post>

 

如果这个处理函数是一个方法,那么这个值将作为参数被传入

<blog-post

  ...

  v-on:enlarge-text="onEnlargeText"

></blog-post>



methods: {

  onEnlargeText: function (enlargeAmount) {

    this.postFontSize += enlargeAmount

  }

}
 

自定义事件

事件名

不同于组件和prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。

v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。

因此,我们推荐你始终使用 kebab-case 的事件名。

 

自定义组件的v-model

一个组件上的v-model会利用value的prop和input的事件,但是像单选框,复选框等类型的输入控件可能会将value特性用在不同的地方(亲测,当勾选单选框或者复选框的时候,值都为undefined)。

所以如果我们想要获得这个值(就是究竟有没有被选中的时候,就可以利用组件的这个model属性)

首先给组件添加model属性,可以看到下面的model含有checked这个属性以及change的这个事件,当组件被改变状态的时候,就会触发这个change事件,并且将自己的checked的值传给父元素,也就是base-checkbox里面的lovingVue这个值绑定了组件中的chencked所对应的值,当base-checkbox触发一个change事件并且附带一个新的值的时候,lovingVue就会被更新。需要注意的是,仍然需要在组件的props里面声明checked这个属性。

Vue.component('base-checkbox', {

  model: {

    prop: 'checked',

    event: 'change'

  },

  props: {

    checked: Boolean

  },

  template: `

    <input

      type="checkbox"

      v-bind:checked="checked"

      v-on:change="$emit('change', $event.target.checked)"

    >

  `

})

 

<base-checkbox v-model="lovingVue"></base-checkbox>

 

将原生事件绑定到组件(.native)

组件根元素直接监听事件(亲测,不添加.native是不生效的),

<div id="test">

    <myinput @focus.native="console"></myinput>

</div>

 

Vue.component("myinput",{

    template:"<input type='text' />"

})

let vm = new Vue({

    el:"#test",

    data:{

 

    },

    methods:{

        console:function () {

            console.log("focus");

        }

    }

});

 

但有的时候组件的根元素不具有这些原生事件的时候,这个事件触发函数就不会生效,例如

<label>

  {{ label }}

  <input

    v-bind="$attrs"

    v-bind:value="value"

    v-on:input="$emit('input', $event.target.value)"

  >

</label>

 

于是vue提供了一个$listeners 属性,里面包含了所有作用在这个组件的监听器

{

  focus: function (event) { /* ... */ }

  input: function (value) { /* ... */ },

}

 

于是上面修改为

Vue.component('base-input', {

  inheritAttrs: false,

  props: ['label', 'value'],

  computed: {

    inputListeners: function () {

      var vm = this

      // `Object.assign` 将所有的对象合并为一个新对象

      return Object.assign({},

        // 我们从父级添加所有的监听器

        this.$listeners,

        // 然后我们添加自定义监听器,

        // 或覆写一些监听器的行为

        {

          // 这里确保组件配合 `v-model` 的工作

          input: function (event) {

            vm.$emit('input', event.target.value)

          }

        }

      )

    }

  },

  template: `

    <label>

      {{ label }}

      <input

        v-bind="$attrs"

        v-bind:value="value"

        v-on="inputListeners"

      >

    </label>

  `

})

 

 

5)在自定义组件里面使用v-model,一定要做一下两件事

将其value属性绑定在一个value的props上

在其input事件被触发的时候,将新的值通过自定义的input事件抛出

 

Vue.component('custom-input', {

  props: ['value'],

  template: `

    <input

      v-bind:value="value"

      v-on:input="$emit('input', $event.target.value)"

    >

  `

})

 

<custom-input v-model="searchText"></custom-input>

 

6)对于特殊的html元素中,其内部元素为指定的元素,所以当我们自定义的元素出现在这里的时候会被视为无效的内容。

此时使用is属性

<table>

  <tr is="blog-post-row"></tr>

</table>

 

7)组件名

全局注册的时候第一个参数就是组件名

Vue.component('my-component-name', { /* ... */ })

 

定义组件名的方式有两种:

使用 kebab-case  

Vue.component('my-component-name', { /* ... */ })

使用 PascalCase

Vue.component('MyComponentName', { /* ... */ })

当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 <my-component-name> 和 <MyComponentName> 都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。

因为HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

<div id="todo-list-example">

    <custom-input v-model="searchText"></custom-input>

    <p>{{searchText}}</p>

</div>

 

Vue.component('CustomInput', {

      props: ['value'],

      template: `

  <input

    v-bind:value="value"

    v-on:input="$emit('input', $event.target.value)"

  >

`

  })

 

  new Vue({

      el: '#todo-list-example',

      data: {

          searchText:""

      }

  })

 

 

但是,使用首字母大写的情况下就会出错

<div id="todo-list-example">

    <CustomInput v-model="searchText"></CustomInput>

    <p>{{searchText}}</p>

</div>

 

 

 

 

8)插槽

所谓插槽,就是在自定义组件中包含的内容,例如

<myelement>something intresting</myelement>

那么上面的something..就是插槽

 

官网中写道,如果不在自定义组件中添加<slot></slot>元素,那么所有被放进来的元素将会被抛弃。

例如上面的myelement模板实现可能如下

<a

  v-bind:href="url"

  class="nav-link"

>

  <slot></slot>

</a>

 

这样写,当组件渲染的时候,这个slot元素就会代替上面的something intresting

 

插槽中可以包含任何模板代码,包括html

<navigation-link url="/profile">

  <!-- 添加一个 Font Awesome 图标 -->

  <span class="fa fa-user"></span>

  Your Profile

</navigation-link>

 

 

具名插槽

结合父组件上使用slot从而指定插槽的位置,例如

模板中的内容可能如下,每个位置拥有不一样的元素

<div class="container">

  <header>

    <slot name="header"></slot>

  </header>

  <main>

    <slot></slot>

  </main>

  <footer>

    <slot name="footer"></slot>

  </footer>

</div>



那么我们在使用父组件的时候

<base-layout>

  <template slot="header">

    <h1>Here might be a page title</h1>

  </template>



  <p>A paragraph for the main content.</p>

  <p>And another one.</p>



  <template slot="footer">

    <p>Here's some contact info</p>

  </template>

</base-layout>
可以看到父组件里面的模板就会出现在slot里面name属性所对应的位置下面

 

如果不像上面,用template元素以及slot属性包裹,直接用在一个普通元素上但是结合slot属性使用,也可以

<base-layout>

  <h1 slot="header">Here might be a page title</h1>

 

  <p>A paragraph for the main content.</p>

  <p>And another one.</p>

 

  <p slot="footer">Here's some contact info</p>

</base-layout>

 

我们还是可以保留一个未命名插槽,这个插槽是默认插槽,也就是说它会作为所有未匹配到插槽的内容的统一出口

 

插槽的默认内容

有的时候为插槽提供的内容是很有用的,例如,个 <submit-button> 组件可能希望这个按钮的默认内容是“Submit”,但是同时允许用户覆写为“Save”、“Upload”或别的内容。

你可以在组件模板里的 <slot> 标签内部指定默认的内容来做到这一点。

<button type="submit">

  <slot>Submit</slot>

</button>

如果父组件为这个插槽提供了内容,那么这个默认的内容就会被替换掉

 

 

 

 

 

9)动态组件&异步组件

在一个多标签的界面中使用is特性来切换不同的组件

Vue.component('tab-home', {

    template: '<div>Home component</div>'

})

Vue.component('tab-posts', {

    template: '<div>Posts component</div>'

})

Vue.component('tab-archive', {

    template: '<div>Archive component</div>'

})

 

new Vue({

  el: '#dynamic-component-demo',

  data: {

    currentTab: 'Home',

    tabs: ['Home', 'Posts', 'Archive']

  },

  computed: {

    currentTabComponent: function () {

      return 'tab-' + this.currentTab.toLowerCase()

    }

  }

})

 

 

 

<div id="dynamic-component-demo" class="demo">

  <button

    v-for="tab in tabs"

    v-bind:key="tab"

    v-bind:class="['tab-button', { active: currentTab === tab }]"

    v-on:click="currentTab = tab"

  >{{ tab }}</button>

 

  <component

    v-bind:is="currentTabComponent"

    class="tab"

  ></component>

 

这样实现的话,每次切换,都会重新渲染的。

当在这些组件进行切换的时候,有时会想保持这些组件的状态,以免反复重新渲染所导致的性能问题,为了解决这个问题,用一个keep-alive元素将动态组件包裹起来

<!-- 失活的组件将会被缓存!-->

<keep-alive> 

<component

    v-bind:is="currentTabComponent"

    class="tab"

  ></component>

</keep-alive>

 

异步组件

所谓异步组件就是等到需要的时候,才会去服务器加载这个模块。vue用工厂函数的的方式定义组件,这个函数会异步的解析运行,也就是只有在需要被渲染的时候才会触发这个函数。

Vue.component('async-example', function (resolve, reject) {

  setTimeout(function () {

    // 向 `resolve` 回调传递组件定义

    resolve({

      template: '<div>I am async!</div>'

    })

  }, 1000)

})

 

 

 

我们来写一个类似于公众号历史记录这样的东西(就是div结构,样式都一样,仅仅是内容不一样的多个div)

<div class="unit">

    <div class="content">

        <h1>这是文章的标题</h1>

        <div class="info">

            <span>2018年11月14日</span>

            <span>原创</span>

        </div>

    </div>

    <img src="img/logo.jpg">

</div>

.unit{

    height: 200px;

    width: 90%;

    overflow: hidden;

    margin: 0 auto;

    background-color: #ffffff;

}

.content{

    width: 60%;

    height: 100%;

    float: left;

}

img{

    width: 40%;

    height: 100%;

    float: left;

}

.info{

    font-size: 16px;

    color: #cccccc;

}

.info span{

    margin: 0 15px;

}

.info span:nth-child(2){

    border: 1px solid #cccccc;

    border-radius: 7px;

}




其中基本的css代码和html的代码如下:下来定义一个组件,代码如下:,这个组件名叫myarticle,拥有props属性和template属性,其中pros属性用来接收参数,这些参数会在模板里面用到。

Vue.component('myarticle',{

    props:['detail'],

    template :' <div class="unit">\n' +

    '        <div class="content">\n' +

    '            <h1>{{detail.title}}</h1>\n' +

    '            <div class="info">\n' +

    '                <span>{{detail.date}}</span>\n' +

    '                <span v-show="detail.is_oringinal">原创</span>\n' +

    '            </div>\n' +

    '        </div>\n' +

    '        <img :src="detail.imgurl">\n' +

    '    </div>'

});
 

然后创建一个vue实例,需要注意的是,一定要确保实例vm在创建之前,组件已经成功注册。

let vm = new Vue({

    el:"#app",

    data:{

        articles:[

            {

                title:"这是第一个标题",

                date:"2018年11月14日",

                is_oringinal:true,

                imgurl:"img/logo.jpg"

            },

            {

                title:"这是第二个标题",

                date:"2018年11月15日",

                is_oringinal:true,

                imgurl:"img/logo.jpg"

            },

            {

                title:"这是第三个标题",

                date:"2018年11月16日",

                is_oringinal:true,

                imgurl:"img/logo.jpg"

            }

        ]

    }

})
注册完组件之后,就开始使用这个自定的组件

<div id="app">

    <myarticle v-for="item in articles" :detail = "item"></myarticle>

</div>

 

 

 

 

八.组件之间的通信

 

组件实例的作用域都是孤立的,也就是子组件在模板中不能引用父组件的数据。

1.父->子,父组件将数据传递给子组件

先创建一个实例

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

<script>

    //创建一个vue实例

  const app = new Vue({

        el:"#app",

        data:{

            msg:"我是父组件的数据哦嘻嘻嘻"

        }

    });

</script>

实例中含有数据msg。

注册子组件

Vue.component('son',{

    template:"<div></div>"

})

并将子组件插入到父组件下面:

<div id="app">

    <son></son>

</div>

 

接下来我们开始传递数据,父组件向子组件传递参数,用组件提供的props属性,在下面的代码中,父组件app向son组件的:message属性传输了它自己的值msg。子组件message接收了这个参数,然后在组件的定义里面,用props来接收这一个值,并将这个值在div中输出。这样就完成了父组件传递给子组件了。props选项声明了它要接受的参数是message,而接收到的对应的值是父组件的数据msg。我们在子组件顺利地把message展示出来。

<div id="app">

    <son :message = "msg"></son>

</div>

Vue.component('son',{

    props:['message'],

    template:"<div>{{message}}</div>"

})

 

 

而props是单向绑定的,也就是说子组件接收到这个值之后无论怎么修改,父组件中也不会受到影响。因为vue为了防止子组件无意修改了父组件的数据和状态,如果多个子组件任意地对父组件进行修改,会让数据流难以阅读。

 

2.子->父,子组件传数据给父组件。

父组件监听子组件的事件,并接收子组件传过来的数据

vue实例都有一个事件的接口,这个接口就是$emit(eventname)来触发一个事件

1.注册一个新组件

Vue.component('son',{

   template:`<button @click="send">

 

               点击

 

            </button>`,

 

   methods:{

       send(){

           this.$emit('connect');

 

       }

   }

});

一个按钮button,点击它的时候,会触发组件内部的send( )方法,而方法体里面会触发一个事件,事件名取名为:“connect”。

然后我们就去父组件监听这个事件‘connect’,监听方式跟普通原生的事件一模一样,也是用 v-on 指令,缩写用@符号。 我们采用缩写来监听:

<div id="app">

    <son @connect="say"></son>

</div>

const app = new Vue({

    el:"#app",

    methods:{

        say(){

            console.log(`大家好,我监听到了

  事件connect的触发`);

        }

    }

});

 

这样,当点击按钮的时候,就成功调用了父组件的say函数。这时,我们只需要把子组件的数据,通过这个事件connect传递给父组件,就可以实现子->父的通信。在data函数里面返回需要返回的数据,并在$emit里面讲msg一并发射出去,在父组件中的say中接收

Vue.component('son',{

    props:['message'],

    template:"<button @click = 'send'>点击</button>",

    data(){

        return{

            msg:'大家好,我是儿子的数据'

        }

    },

    methods:{

        send(){

            this.$emit('connect',this.msg);

        }

    }

})

const  app = new Vue({

    el:"#app",

    methods:{

        say(msg){

            console.log("hello,我监听到了子组件的connect事件的触发,儿子的数据是"+msg);

        }

    }

})

 

这样就完成了子->父组件的数据传输

 

 

九.动态绑定class和style

1.class的绑定

1)对象法:动态绑定的class的值是一个对象{},键是一个样式名,而值是是否显示这个样式。在对象中,若该属性对应的value为true,则该属性会被渲染出来,为false,则不会渲染出来。并且这写法可以与单独的class属性可以共存

<p :class="{'active':isActive}">这是文字</p>

<p :class="{'active':notActive}">这是文字</p>

<p class="static" :class="{'active':isActive}}"></p>

let  vm = new Vue({

    el:"#app",

    data:{

        isActive:true,

        error:"active",

        active:"erro",

        color:"red",

        ifshow:"block",

    }

})

 

2)数组法,数组语法中也可以使用对象语法:

<p :class="[active,errorc]">hello</p>

数组中的值在实例中对应的值是一个属性样式,也就是说数组法中html中数组的值可以不是一个样式名,只要它在vue实例中data中对应的键值的值是一个样式名。

 

 

 

 

2.style的绑定(绑定内联样式style)

CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名:

1)对象语法,需要注意的是这样绑定的属性之间要用逗号隔开,不要用分号

<p :style="{color:color,display:ifshow}">world</p>

 

 

2)数组语法

v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上:

<div v-bind:style="[baseStyles, overridingStyles]"></div>

 

当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS 属性时,如 transform,Vue.js 会自动侦测并添加相应的前缀。

 

你可以为 style 绑定中的属性提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:

<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex。

 

3.用在组件上

当在一个自定义组件上使用class属性的时候,这些类将被添加到该组件的根元素上面。这个元素上已经存在的类不会被覆盖。

例如,如果你声明了这个组件:

Vue.component('my-component', {

  template: '<p class="foo bar">Hi</p>'

})

然后在使用它的时候添加一些 class:

<my-component class="baz boo"></my-component>

HTML 将被渲染为:

<p class="foo bar baz boo">Hi</p>

对于带数据绑定 class 也同样适用:

<my-component v-bind:class="{ active: isActive }"></my-component>

当 isActive 为 truthy 时,HTML 将被渲染成为:

<p class="foo bar active">Hi</p>

 

 

 

 

 

 

十.demo,做一个TODOlist

确定T

 

 

 

十一.用transition组件轻松实现过渡效果

1.transition过度原理分析

vue提供的transition组件会在以下四种情况下起作用

条件渲染(v-if)

条件展示(v-show)

动态组件

组件根节点

在上述的任意一种情况发生的时候(比如v-show的值本来为true的时候,当发生某种变化导致值变为false的时候),就可以给transition组件包含的节点元素添加enter或leave过度动画元素。

当插入或删除包含在transition组件中的元素时,vue将会做以下的处理

自动嗅探目标元素是否应用了css过渡或动画,如果是,在适当的时候添加或者删除css类名

如果过渡组件提供了JavaScript钩子函数,这些钩子函数将会在恰当的时机被调用

如果没有找到JavaScript钩子也没有检测到css过渡/动画,dom操作在下一帧立即执行

 

下面的v在实际应用改成transition中name属性的值

v-enter:定义过渡的开始状态,在元素被插入之前生效,在元素被插入之后的下一帧移除。

v-enter-active:定义过渡生效时的状态,在整个进入过渡的阶段都会应用,在元素被完全插入之前生效,在过渡或者动画完成之后被移除。(就是这个类来定义过渡的时间等)

v-enter-to:定义过渡的结束状态,在元素被插入之后下一帧生效,在过渡或者动画完成之后被移除。

v-leave:离开过渡的开始的那一刻(用在从显示到隐藏的时候)

v-leave-active:离开过渡的的持续状态,在整个离开过渡的阶段中应用(在这里定义过渡的时间等)

v-leave-to离开过渡的结束状态,在离开过渡被触发之后下一帧生效。

 

需要注意的是

节点一定要被transition元素包含

transition的name属性一定要与css类名开始的地方相同(如果没有使用name属性,那么类名前缀为v)

2.例子

<div id="test">

   <button @click="show = !show">toggle</button>

    <transition name="fade">

        <p v-if="show">hello</p>

    </transition>

</div>

<script>

  let vm = new Vue({

    el:"#test",

    data:{

        show:false

    }

});

</script>

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

    /*定义过渡的状态*/

    transition: all 1.5s ease;

}

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

    /*定义进入动画的状态,以及离开动画最后结束的状态*/

    transform: translateX(20px);

}

 

 

(2)css动画

在动画中,v-enter类名在节点插入dom后不会立即删除,而是在animationend时间触发时删除。

(也就是说,直到触发动画事件的时候才会删除这个类名)

 

.animate-enter-active{

    animation: bounze 1s;

}

.animate-leave-active{

     animation: bounze 1.5s reverse;

}

@keyframes bounze {

   0%{

   transform: translateX(0px);

   }

     50%{

         transform: translateX(20px);

     }

     100%{

   transform: translateX(40px);

     }

}

 

(3)自定义过渡类名

可以通过自定义类名来使用其他第三方css动画库里面的类名(在transition元素上面指定自定义的类名)

* enter-class

* enter-active-class

* enter-to-class (2.1.8+)

* leave-class

* leave-active-class

* leave-to-class (2.1.8+)

<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">

 

<div id="example-3">

  <button @click="show = !show">

    Toggle render

  </button>

  <transition

    name="custom-classes-transition"

    enter-active-class="animated tada"

    leave-active-class="animated bounceOutRight"

  >

    <p v-if="show">hello</p>

  </transition>

</div>

 

(4)JavaScript钩子

就是在transition 过渡或者动画中使用JavaScript的的处理函数进行处理,有一下八个钩子

before-enter

enter

after-enter

enter-cancelled

before-leave

leave

after-leave

leave-cancelled

 

<transition

  v-on:before-enter="beforeEnter"

  v-on:enter="enter"

  v-on:after-enter="afterEnter"

  v-on:enter-cancelled="enterCancelled"

 

  v-on:before-leave="beforeLeave"

  v-on:leave="leave"

  v-on:after-leave="afterLeave"

  v-on:leave-cancelled="leaveCancelled"

>

  <!-- ... -->

</transition>

 

 

// ...

methods: {

  // --------

  // 进入中

  // --------

 

  beforeEnter: function (el) {

    // ...

  },

  // 当与 CSS 结合使用时

  // 回调函数 done 是可选的

  enter: function (el, done) {

    // ...

    done()

  },

  afterEnter: function (el) {

    // ...

  },

  enterCancelled: function (el) {

    // ...

  },

 

  // --------

  // 离开时

  // --------

 

  beforeLeave: function (el) {

    // ...

  },

  // 当与 CSS 结合使用时

  // 回调函数 done 是可选的

  leave: function (el, done) {

    // ...

    done()

  },

  afterLeave: function (el) {

    // ...

  },

  // leaveCancelled 只用于 v-show 中

  leaveCancelled: function (el) {

    // ...

  }

}

当仅仅使用JavaScript过渡的时候,需要有两个注意事项

在enter和leave中必须使用done来进行回调

在transition中使用v-bind:css="false",这样vue会跳过css的检测。

 

(5)初始渲染的过渡

可以通过appear特性来设置节点在初始渲染的过渡

 

(6)多个元素的过渡

就是多个元素之间只显示其中一个,当状态发生改变的时候,显示的元素不一样,就会出现元素之间的过渡。值得注意的是,官网推荐在相同标签名的元素之间进行切换的时候,需要给这些元素设置key特性,并拥有不一样的值,否则vue为了效率只会替换相同标签内部的内容。

<button v-if="isEditing" @click="isEditing = !isEditing" key="save">

    Save

</button>

<button v-else @click="isEditing = !isEditing" key="edit">

    Edit

</button>

 

此外,在vue中,当两个元素进行过度的时候,transition的默认行为是进入和离开同时发生,那么此时两个元素就都会同时发生过度效果,这会影响效果,所以vue中有一个过渡模式

这个模式有两个值,分别是

out-in 离开元素先过渡然后再到进入的元素过渡

in-out 与上面相反

<transition name="mutiple" mode="out-in">

    <button v-if="isEditing" @click="isEditing = !isEditing" key="save">

        Save

    </button>

    <button v-else @click="isEditing = !isEditing" key="edit">

        Edit

    </button>

</transition>

 

(6)多个组件的过渡

多个组件的过渡使用动态组件

 

  Vue.component("tab-home",{

      template:`<p>this is home</p>`

  });

  Vue.component("tab-aboutus",{

      template:`<p>this is aboutus</p>`

  });

  Vue.component("tab-vechicle",{

      template:`<p>this is vechicle</p>`

  });

let vm = new Vue({

    el:"#test",

    data:{

        buts:["home","aboutus","vechicle"],

        currentTab:"home"

    },

    computed:{

        currentActiveTab:function () {

            return "tab-"+this.currentTab;

        }

    }

});

 

<div id="test">

        <button v-for="but in buts" @click="currentTab = but" :key="but">

            {{but}}

        </button>

    <transition name="mutiple" mode="out-in">

       <keep-alive>

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

       </keep-alive>

    </transition>

</div>

 

(7)列表过渡

使用transition-group组件包含列表元素

使用transition-group的特点

不同于transition,它会以一个真实的元素呈现,默认为一个span,可以通过tag特性来更改为其他元素

过渡模式不可以用,因为不再切换其他元素

内部元素总是需要有一个唯一的key属性

new Vue({

    el: '#list-demo',

    data: {

        items: [1,2,3,4,5,6,7,8,9],

        nextNum: 10

    },

    methods: {

        randomIndex: function () {

            return Math.floor(Math.random() * this.items.length)

        },

        add: function () {

            this.items.splice(this.randomIndex(), 0, this.nextNum++)

        },

        remove: function () {

            this.items.splice(this.randomIndex(), 1)

        },

    }

})

 

<div id="list-demo" class="demo">

    <button v-on:click="add">Add</button>

    <button v-on:click="remove">Remove</button>

    <transition-group name="mutiple" tag="p">

    <span v-for="item in items" v-bind:key="item" class="mutiple-item">

      {{ item }}

    </span>

    </transition-group>

</div>

 

.mutiple-item {

    display: inline-block;

    margin-right: 10px;

}

.mutiple-enter-active,.mutiple-leave-active{

   transition: all 1s ;

}

.mutiple-enter,.mutiple-leave-to{

    transform: translateY(10px);

}

 

列表的排序过渡,transition-group组件还有一个特殊之处,不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需要了解新增的v-move特性,他会在元素的改变定位的过程中应用。

css的类名可以使用name属性自定义前缀,也可以通过move-class属性手动设置。

 

 

 

 

十二.vue-router

1.vue-router是vue官方的路由插件,适合用于构建单页面应用。

2.先引入vue-router

3.准备组件,vue-route给我们提供了两个新组件,<router-link>和<router-link>组件,其中link是用于帮助用户进行视图导航,也就是传统页面中a标签所做的事情,用to来指定组件的位置。而view组件负责渲染匹配到的视图组件,也就是渲染link指向的目标地址,

<div id="app">

    <div class="nav">

        <router-link to="/hins">张敬轩</router-link>

        <router-link to="/ste">孙燕姿</router-link>

        <router-link to="/adele">Adele</router-link>

    </div>

    <div class="content">

        <router-view></router-view>

    </div>

</div>

 

接下来定义视图组件以及与导航地址关联起来。创建一个router实例,创建实例的时候我们需要传参数routes来进行配置。

const hins = {

    template:`<div>这是张敬轩的页面</div>`

};

const ste = {

    template:`<div>这是孙燕姿</div>`

};

const  adele = {

    template:`<div>这是Adele</div>`

};

const router = new VueRouter({

    routes:[

        {

            path:"/hins",

            component:hins

        },

        {

            path:"/ste",

            component:ste

        },

        {

            path:"/adele",

            component:adele

 

        }

    ]

});

 

 

最后,创建一个vue实例,创建的时候通过配置router参数来注入我们刚定义好的router路由

 

//创建vue实例,注入路由router

const app = new Vue({

    el:"#app",

    router //此处是ES6语法,

 

 

      //相当于router:router

});

 

 

 

 

 

 

 

 

十三.vuex

1.vuex是什么?

vuex是一个专为vue开发的应用程序的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex采用类似全局对象的形式来管理所有组件的公用数据,如果你想想修改这个全局对象的数据?是可以的,但没那么简单,你得按照Vuex提供的方式来修改,不能自己随意用自己的方式来修改

 

(1)vue的状态存储是响应式的,方你的组件使用到了这个vuex的状态,一旦它改变了,所有关联的组件都会自动更新相对应的数据。

(2)不能直接修改vuex的状态,想修改就得使用vuex提供的唯一途径:显示地提交mutations来实现修改,

 

2.vuex的3个核心概念

(1)要使用vuex,就要创建一个实例store,我们称之为仓库,利用这个仓库对状态进行管理

const store = new Vuex.Store({});

 

(2)State

vuex使用单一状态树,用一个对象state包含了整个应用层级的所有状态。在下面代码中,假如我们有一个全局状态count,值为5,就可以将其定义为state对象里面的一对键值对,作为全局状态供我们使用。

const store = new Vuex.Store({

    state:{

        count:5

    }

});

 

(2)Getters

当我们需要从state中派生出一些状态的时候,就会使用到getters,相当于getters是state的计算属性。

const store = new Vuex.Store({

    state:{

        count:5

    },

    getters:{

        newCount:state =>state.count*3

    }

 

});

 

(3)mutations

vuex给我们提供修改仓库store中的状态的唯一方法就是通过提交mutation。

定义一个mutations:

const store = new Vuex.Store({

    state:{

        count:5

    },

    getters:{

        newCount:state =>state.count*3

    },

    mutations:{

        increment(state){

            state.count ++;

        }

    }

 

});

 

定义好了后就必须要提交mutation,语法如下:

store.commit('increment');

 

4.例子

需求:做一个计算器,那么运算的结果result和输入的值enter就是会跟每一个组件(按键)

相关联的,所以这里我们将result和enter作为应用层的状态(全局数据)来处理,这里就会简单的使用到vuex提供的仓库store。

 

首先完成上面界面的实现。

一共有3个主要区域,一个运算的结果,一个输入的结果,还有按键区域。

按键区域的使用可以使用组件来实现,定义一个keyboard组件,根据传入的参数来定义不一样的按键。

<div id="app">

    <div class="result"></div>

    <div class="enter"></div>

    <div class="keys">

        <div class="list">

            <keyboard v-for="item in keys" :value="item"></keyboard>

        </div>

    </div>

</div>

<script>

    Vue.component("keyboard",{

        props:['value'],

        template:`<div

           :data-value="value">

            {{value}}

         </div>`

    });

   

    const app = new Vue({

        el:"#app",

        data:{

            keys:[

                'clear','+','-','*',

                '7','8','9','/',

                '4','5','6','0',

                '1','2','3','=',

            ]

        }

    });

 

</script>

 

#app{

    width: 100%;

    height: 100%;

}

.result{

    width: 324px;

    height: 56px;

    font-size: 34px;

    margin-left: 178px;

}

.enter{

    width: 324px;

    height: 50px;

    font-size: 24px;

    margin-left: 218px;

}

.keys{

    width: 324px;

    height: 324px;

}

.list div{

    width: 80px;

    height: 80px;

    line-height: 80px;

    background-color: #efefef;

    border: 0.5px solid #cccccc;

    border-bottom: none;

    border-right: none;

    float: left;

    text-align: center;

    font-size: 18px;

    vertical-align: center;

}

.list div:first-child{

    color: #ff8282;

}

.list div:last-child{

    color: white;

    background-color: #ff8282;

}

 

 

界面实现了,接下来就是数据的显示以及如何进行数据绑定,当按键被按下的时候,显示输入的值以及运算的结果。这时候,组件们就共用到了result和enter这两个值,所以我们首先需要建立仓库来管理它们,并初始化为空字符串

const store = new VUex.Store({

    state:{

        result:"",

        enter:""

    }

})

 

vuex提供了store选项,允许我们将仓库store引入到根组件中,并且此跟组件的所有子组件都可以使用仓库store,而且子组件无需显示的引入。

首先我们在vue实例下面引入我们的仓库store

 

const app = new Vue({

    el:"#app",

    data:{

        keys:[

            'clear','+','-','*',

            '7','8','9','/',

            '4','5','6','0',

            '1','2','3','=',

        ]

    },

    store,

 

}

引入之后我们就来使用,那么怎么使用仓库的result和enter呢?我们这里用到vue的computed计算属性。通过this.$store来回去仓库,然后this.$store.state来获取属性,最后用this.$store.state.result来获取仓库里的result。同理获得enter

computed:{

    result(){

        return this.$store.state.result;

    },

    enter(){

        return this.$store.state.enter;

    }

}

 

将result和enter显示在html代码里面

<div class="result">{{result}}</div>

<div class="enter">{{enter === ""?0:enter}}</div>

 

最后,绑定按键的点击事件,当我们点击键盘的时候,对仓库的result和enter进行修改。但是vuex中不能任意修改应用层的状态,所以就通过它提供的唯一的途径:通过commit提交mutation。当用户点击键盘的时候我们就提交一个mutation,并把当前按的键对应的值传过去。所以我们要重新定义keyboard组件的事件。

Vue.component("keyboard",{

    props:['value'],

    template:`<div

        @click="getKeyboardValue"

       :data-value="value">

        {{value}}

     </div>`,

    methods:{

        getKeyboardValue(event){

            let value=event.target.dataset.value;

            this.$store.commit('calculate',value)

        }

    }

});

 

增加了一个监听点击事件的处理函数getKeyboardValue,我们会提交体格名为calculate的mutation给仓库,并将当前按键的值一起提交过去。这个calculate的mutation要在仓库中定义

const store = new Vuex.Store({

    state:{

        result:"",

        enter:""

    },

    mutations:{

        calculate(state,value){

            if (value === '='){

                state.result = eval(state.enter);

                state.enter+=value;

            }else if (value === 'clear'){

                state.result = state.enter = "";

            }else {

                state.enter +=value;

            }

        }

    }

});

 

 

 

十四.使用axios

(1)get请求

 

axios.get('detail.html?id=10').then(function (res) {

    console.log(res);

}).catch(function (err) {

    console.log(err);

});

 

 

 

axios.get('detail.html',{

    params:{

        id :10

    }

}).then(function (res) {

    console.log(res);

}).catch(function (err) {

    console.log(err)

})

 

 

(2)post请求

 

 

axios.post('detail.html',{

    name:"krys",

    age:22

}).then(function (res) {

    console.log(res)

}).catch(function (err) {

    console.log(err);

})

 

(3)多个请求并发

 

function getProfile(){

    //请求1

    return axios.get('vuex.html');

}

function getUser(){

    //请求2

    return axios.get('todo.html');

}

 

//并发请求

axios.all([

    getProfile(),

    getUser()

]).then(axios.spread((res1, res2)=>{

    //两个请求现已完成

    console.log(res1);

    console.log(res2);

}));

 

 

 

我们事先定义了两个方法getProfile()和getUser()帮我们实现get请求。在某个业务场景中,我们需要同时产生以上两个get请求,并需要等待它们都请求完毕后再做逻辑处理,你也许会想到回调嵌套,但现在你可以使用axios的并发请求API: axios.all()

当这两个请求都完成的时候会触发 axios.spread() 函数,res1和res2两个参数分别代表返回的结果,相当实用的API。

 

上面的写法当中是axios提供给我们的别名写法,也可以写成下面这样

axios({

    method: 'post',

    url: 'detail.html',

    data: {

        name: 'krys',

    }

});

 

 

 

十五、官网上看到的一些总结

1.使用object.freeze()会阻止修改现有的属性,也就是说,当代码中使用了Object.freeze(obj),那么在vue实例中将不会再追踪这个对象的变化。(仅仅针对data属性中的值是外部的一个对象)

<div id="app">

  <p>{{ foo }}</p>

  <!-- 这里的 `foo` 不会更新! -->

  <button v-on:click="foo = 'baz'">Change it</button>

</div>

 

var obj = {

  foo: 'bar'

}

Object.freeze(obj);

new Vue({

  el: '#app',

  data: obj

})

 

 

2.混入

(1)什么是混入?

混入(mixins)是一种分发vue组件中可以重复使用的功能的方式。

混入对象可以包含任意组件选项。当组件使用混入对象是,所有混入独享的选项将被混入该组件本身的选项。(其实就是多个组件中相同功能的部分)

 

组件在引用之后相当于在父组件内开辟了一块单独的空间,来根据父组件props过来的值进行相应的操作,单本质上两者还是泾渭分明,相对独立。

 

而mixins则是在引入组件之后,则是将组件内部的内容如data等方法、method等属性与父组件相应内容进行合并。相当于在引入后,父组件的各种属性方法都被扩充了。

 

 

 

(2)当组件和混入对象含有同名选项的时候,以下面这些方式进行混合

数据对象在内部会进行递归合并,在和组件的数据发生冲突的时候以组件数据为优

同名钩子函数将混为同一个数组,因此两个都会被调用,但是混入对象的钩子将会在组件自身钩子之前被调用

值为对象的选项,例如methods,components等将会被混合为同一个对象,当两个对象里面属性名冲突的时候,取组件对象的键值对

var mixin = {

     data: function () {

         return {

             message: 'hello',

         }

     },

     created: function () {

         console.log('混入对象的钩子被调用')

     },

     methods: {

         foo: function () {

             console.log('foo')

         },

         conflicting: function () {

             console.log('from mixin')

         }

     }

};

 

let vm =  new Vue({

     el:"#list-demo",

     mixins: [mixin],

     data: function () {

         return {

             message: 'goodbye',

         }

     },

     created: function () {

         console.log('组件的钩子被调用')

     },

     methods:{

         bar: function () {

             console.log('bar')

         },

         conflicting: function () {

             console.log('from self')

         }

     }

});

vm.foo() // => "foo"

vm.bar() // => "bar"

vm.conflicting() // => "from self"

 

(3)全局混入

 

全局声明混入对象,在全局混入对象中声明的属性,会影响所有的vue实例。

全局声明混入对象的代码

// 为自定义的选项 'myOption' 注入一个处理器。

Vue.mixin({

  created: function () {

    var myOption = this.$options.myOption

    if (myOption) {

      console.log(myOption)

    }

  }

})

 

let vm =  new Vue({

    el:"#list-demo",

    data: function () {

        return {

            message: 'goodbye',

        }

    },

    myOption:"hello"

});

这样控制台会立即打印出hello

大多数情况下,只应当应用于自定义选项,就像上面示例一样。

 

 

3.自定义指令

自定义全局指令

Vue.directive("myfirst",{

    inserted:function (el) {

        el.focus();

    }

});

自定义局部指令

directives: {

  focus: {

    // 指令的定义

    inserted: function (el) {

      el.focus()

    }

  }

}

然后可以在模板中的任何元素上面使用

<input v-myfirst>

 

 

此外,指令定义对象有如下几个钩子函数(均为可选)

bind:只调用一次,指令第一次绑定到元素时调用

inserted:被绑定你元素插入父节点时调用(也就是dom生成的时候调用)

update:所在组件爱你的vnode更新时调用

componentUpdated所在组件的vnode及其子vnode全部更新后调用

unbind:只调用一次,指令与元素解绑时调用

 这些钩子函数会被传入下面这些参数

* el:指令所绑定的元素,可以用来直接操作 DOM 。

* binding:一个对象,包含以下属性:

    * name:指令名,不包括 v- 前缀。

    * value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。

    * oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。

    * expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1"中,表达式为 "1 + 1"。

    * arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。

    * modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。

* vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。

* oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

 

4、渲染函数以及JSX

在vue中使用render生成html代码

Vue.component('anchored-heading', {

    render: function (createElement) {

        return createElement(

            'h' + this.level,   // 标签名称

            this.$slots.default // 子元素数组

        )

    },

    props: {

        level: {

            required: true

        }

    }

});

 

(2)虚拟DOM

虚拟节点:包含的信息会告诉vue页面上需要渲染什么样的节点,以及其子节点。如下面会返回一个虚拟及诶单

createElement('h1', this.blogTitle)

 

createElement(

  // {String | Object | Function}

  // 一个 HTML 标签字符串,组件选项对象,或者

  // 解析上述任何一种的一个 async 异步函数。必需参数。

  'div',

 

  // {Object}

  // 一个包含模板相关属性的数据对象

  // 你可以在 template 中使用这些特性。可选参数。

  {

    // (详情见下一节)

  },

 

  // {String | Array}

  // 子虚拟节点 (VNodes),由 `createElement()` 构建而成,

  // 也可以使用字符串来生成“文本虚拟节点”。可选参数。

  [

    '先写一些文字',

    createElement('h1', '一则头条'),

    createElement(MyComponent, {

      props: {

        someProp: 'foobar'

      }

    })

  ]

)

转载链接:https://blog.csdn.net/krysliang/article/details/87284483

posted @ 2021-03-05 16:50  墨秋丶  阅读(258)  评论(0编辑  收藏  举报