赞
踩
1.数据驱动(mvvm模型,只要改变model的数据,视图层就会自动更新)
2.视图组件: 把整一个网页的拆分成一个个区块,每个区块我们可以看作成一个组件。网页由多个组件拼接或者嵌套组成。
1.引入vue之后就可以进行下面的步骤
2.创建语法(创建 ,设置数据,挂载,渲染)
var vm = new Vue({})//参数是一个对象
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,
不要在选项属性或者回调函数上面使用箭头函数,因为箭头函数是和父级上下文绑定在一起的。
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'
}
})
]
)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。