一.vue实例
每个vue应用都是通过Vue
构造函数创建的一个新的实例开始的:
var vm = new Vue({ //选项对象 })
在这其中vm(viewModel的简称)
通常都表示vue实例的变量名。当创建一个vue实例,你都可以传入一个选项对象作为参数,完整的选项对象,你可能需要查看API文档。
一个vue应用应该由一个通过new Vue
构造的根实例和许多可嵌套可复用的组件构成,这也就是说所有的组件都是vue实例。
二.数据与方法
当一个vue实例被创建完成之后,就会向它的vue响应系统中加入了data
对象中能找到的所有属性,当这些属性的值发生改变之后,视图就会发生响应
,也就是更新相应的值。我们来看一个例子:
//源数据对象 var obj = { name:"eveningwater" }; //构建实例 var vm = new Vue({ data:obj }) //这两者是等价的 vm.name === obj.name; //这也就意味着 //修改data对象里的属性也会影响到源数据对象的属性 vm.name = "waterXi"; obj.name;//"waterXi" //同样的,修改源数据对象的属性也会影响到data对象里的属性 obj.name = 'stranger'; vm.name;//"stranger"
可能需要注意的就是,只有data对象中存在的属性才是响应式的,换句话说,你为源数据对象添加一个属性,根本不会影响到data对象。如:
obj.sex = "男"; vm.sex;//undefined obj.sex;//'男' obj.sex = "哈哈哈"; vm.sex;//undefined
这也就意味着你对sex
的修改并不会让视图更新,如此一来,你可能需要在data对象中初始化一些值,如下:
data:{ str:'', bool:false, arr:[], obj:{}, err:null, num:0 }
查看此处具体示例。
只是还有一个例外Object.freeze()
,这个方法就相当于锁定(冻结)一个对象,使得我们无法修改现有属性的特性和值,并且也无法添加新属性。因此这会让vue响应系统无法追踪变化:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>freeze</title> </head> <body> <div id="app"> <span>{{ message }}</span> <button type="button" v-on:click="reverseMessage">反转信息</button> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码如下:
var obj = { message: "hello,vue.js!" } //阻止对象 Object.freeze(obj); var app = new Vue({ el: "#app", data:obj, methods: { reverseMessage: function() { this.message = this.message.split("").reverse().join(""); } } });
如此一来,无论我们怎么点击按钮,都不会将信息反转,甚至页面还会报错,如下图:
可前往此处具体示例自行查看效果。
当然除了数据属性以外,vue还暴露了一些有用的实例属性和方法,它们通常都带有$
前缀,这样做的方式是以便与用户区分开来。来看一个示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>property</title> </head> <body> <div id="app"> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { name:'eveningwater' } var vm = new Vue({ data:obj, }); //这行代码表示将vue实例挂载到id为app的DOM根节点上,相当于在实例的选项对象中的el选项,即 //el:'#app' vm.$mount(document.querySelector('#app')) //数据是相等的 vm.$data === obj;//true //挂载的根节点 vm.$el === document.querySelector('#app');//true //以上两个属性都是实例上的属性,接下来还有一个watch即监听方法是实例上的方法 vm.$watch('name',function(oldValue,newValue){ //数据原来的值 console.log(oldValue); //数据最新的值 console.log(newValue); })
接下来,可以尝试在浏览器控制台修改name
的值,你就会发现watch()
方法的作用了,如下图所示:
这个示例可前往具体示例。
三.实例生命周期
每个vue实例在被创建的时候都会经历一些初始化的过程,这其中提供了一些生命周期钩子函数,这些钩子函数代表不同的生命周期阶段,这些钩子函数的this
就代表调用它的那个实例。对于生命周期,有一张图:
你不需要立即这张图所代表的含义,我们来看一个示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>vue life cycle</title> </head> <body> <div id="app"> <span>vue生命周期</span> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { name:'eveningwater' } var app = new Vue({ data:obj, beforeCreate:function(){ //此时this指向app这个vue实例,但并不能得到data属性,因此this.name的值是undefined console.log('实例被创建之前,此时并不能访问实例内的任何属性' + this.name) } });
关于生命周期的全部理解,我们需要理解后续的组件知识,再来补充,此处跳过。这个示例可前往具体示例
四.模板语法
vue使用基于HTML的模板语法,在vue的底层是将绑定数据的模板渲染成虚拟DOM,并结合vue的响应式系统,从而减少操作DOM的次数,vue会计算出至少需要渲染多少个组件。
最简单的模板语法莫过于插值
了,vue使用的是Mustache语法(也就是双大括号"{{}}")
。这个只能对文本进行插值,也就是说无论是字符串还是标签都会被当作字符串渲染。如:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>Mustache</title> </head> <body> <div id="app"> <span>{{ greeting }}World!</span> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { greeting:"Hello,"}; var vm = new Vue({ data:obj }); vm.$mount(document.getElementById('app'));
如此以来Mustache标签
就会被data对象
上的数据greeting
给替代,而且我们无论怎么修改greeting
的值,视图都会响应,具体示例。
我们还可以使用v-once
指令对文本进行一次性插值,换句话说,就是这个指令让插值无法被更新:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>Mustache</title> </head> <body> <div id="app"> <span v-once>{{ greeting }}World!</span> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { greeting:"Hello,"}; var vm = new Vue({ data:obj }); vm.$mount(document.getElementById('app'));
在浏览器控制台中我们输入vm.greeting="stranger!"
可以看到视图并没有被更新,这就是这个指令的作用,我们需要注意这个指令对数据造成的影响。具体实例
既然双大括号只能让我插入文本,那要是我们要插入HTML代码,我们应该怎么办呢?v-html
这个指令就可以让我们插入真正的HTML代码。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>v-html</title> </head> <body> <div id="app"> <p>{{ message }}</p> <p v-html="message"></p> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { message:"<span style='color:#f00;'>hello,world!</span>"}; var vm = new Vue({ data:obj }); vm.$mount(document.getElementById('app'));
页面效果如图所示;
可前往具体示例。
关于HTML特性,也就是属性,我们需要用到v-bind
指令,例如:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>v-bind</title> </head> <body> <div id="app"> <div v-bind:id="propId">使用v-bind指令给该元素添加id属性</div> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { propId:"myDiv"}; var vm = new Vue({ data:obj }); vm.$mount(document.getElementById('app'));
打开浏览器控制台,定位到该元素,我们就能看到div
元素的id
属性为"myDiv"
,如下图所示:
具体示例。
在绑定与元素实际作用相关的属性,比如disabled
,这个指令就被暗示为true
,在默认值是false,null,undefined,''
等转换成false的数据类型时,这个指令甚至不会表现出来。如下例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>v-bind</title> </head> <body> <div id="app"> <button type="button" v-bind:disabled="isDisabled">禁用按钮</button> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { isDisabled:123}; var vm = new Vue({ data:obj }); vm.$mount(document.getElementById('app'));
这样一来,无论我们怎么点击按钮都没用,因为123
被转换成了布尔值true
,也就表示按钮已经被禁用了,我们可以打开控制台看到:
你可以尝试这个示例具体示例。
在使用模板插值的时候,我们可以使用一些JavaScript表达式。如下例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>expression</title> </head> <body> <div id="app"> <p>{{ number + 1 }}</p> <p>{{ ok ? "确认" : "取消" }}</p> <p>{{message.split("").reverse().join("")}}</p> <div v-bind:id="'my' + elementId"> 元素的id为<span :style="{ 'color':color }">myDiv</span> </div> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { number: 123, ok: true, message: "hello,vue.js!", elementId: "Div", color: "red" }; var vm = new Vue({ data: obj }); vm.$mount(document.getElementById("app"));
这些JavaScript表达式都会被vue实例作为JavaScript代码解析,具体示例。
值得注意的就是有个限制,只能绑定单个表达式,像语句是无法生效的。如下例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>sentence</title> </head> <body> <div id="app"> <p>{{ var number = 1 }}</p> <p>{{ if(ok){ return '确认'} }}</p> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { number: 123, ok: true }; var vm = new Vue({ data: obj }); vm.$mount(document.getElementById("app"));
像这样直接使用语句是不行的,浏览器控制台报错,如下图:
不信可以自己试试具体示例。
指令(Directives)
是带有v-
前缀的特殊特性,通常指令的预期值就是单个JavaScript表达式(v-for除外)
,例如v-if
与v-show
指令,前者表示DOM节点的插入和删除,后者则是元素的显隐。所以,指令的职责就是根据表达式值的改变,响应式的作用于DOM。现在我们来看两个示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>v-if</title> </head> <body> <div id="app"> <p v-if="value === 1">{{ value }}</p> <p v-else-if="value === 2">{{ value }}</p> <p v-else>{{ value }}</p> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { value: 1 }; var vm = new Vue({ el: "#app", data() { return obj; } });
运行在浏览器效果如图:
现在你可以尝试在浏览器控制台更改vm.value = 2
和vm.value = 3
我们就可以看到页面的变化。你也可以狠狠点击此处具体示例查看和编辑。
我们再看v-show
的示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>v-show</title> </head> <body> <div id="app"> <p v-show="value === 1">{{ value }}</p> <p v-show="value === 2">{{ value }}</p> <p v-show="value === 3">{{ value }}</p> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { value:1 } var vm = new Vue({ data:obj }); vm.$mount(document.querySelector('#app'))
然后查看效果如图:
尝试在控制台修改vm.value = 2
和vm.value = 3
我们就可以看到页面的变化。你也可以狠狠点击具体示例查看。
从上面两个示例的对比,我们就可以看出来v-show
与v-if
指令的区别了,从切换效果来看v-if
显然不如v-show
,这说明v-if
有很大的切换开销,因为每一次切换都要不停的执行删除和插入DOM元素操作,而从渲染效果来看v-if
又比v-show
要好,v-show
只是单纯的改变元素的display
属性,而如果我们只想页面存在一个元素之间的切换,那么v-if
就比v-show
要好,这也说明v-show
有很大的渲染开销。
而且v-if
还可以结合v-else-if
与v-else
指令使用,而v-show
不能,需要注意的就是v-else
必须紧跟v-if
或者v-else-if
之后。当需要切换多个元素时,我们还可以使用template
元素来包含,比如:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>template</title> </head> <body> <div id="app"> <template v-if="value > 1"> <p>{{ value }}</p> <h1>{{ value }}</h1> </template> <template v-else> <span>{{ value }}</span> <h2>{{ value }}</h2> </template> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { value: 1 }; var vm = new Vue({ el: "#app", data() { return obj; } });
此时template
相当于一个不可见元素,如下图所示:
尝试在控制台修改vm.value = 2
就可以看到效果了,你也可以狠狠的点击此处具体示例。
对于可复用的元素,我们还可以添加一个key
属性,比如:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>key</title> </head> <body> <div id="app"> <template v-if="loginType === 'username'"> <label>username:</label> <input type="text" key="username" placeholder="enter your username" /> </template> <template v-else-if="loginType === 'email'"> <label>email:</label> <input type="text" key="email" placeholder="enter your email" /> </template> <template v-else> <label>mobile:</label> <input type="text" key="mobile" placeholder="enter your mobile" /> </template> <button type="button" @click="changeType"> toggle login type </button> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { loginType: "username", count:1 }; var vm = new Vue({ el: "#app", data() { return obj; }, methods: { changeType() { this.count++; if (this.count % 3 === 0) { this.loginType = "username"; } else if (this.count % 3 === 1) { this.loginType = "email"; } else { this.loginType = "mobile"; } } } });
效果如图:
你可以狠狠的点击具体示例查看。
从这几个示例我们也可以看出v-if
就是惰性
,只有当条件为真时,v-if
才会开始渲染。值得注意的就是v-if
与v-for
不建议合在一起使用。来看一个示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>v-if与v-for</title> </head> <body> <div id="app"> <ul> <li v-for="(item,index) in list" v-bind:key="index" v-if="item.active"> <span>{{ item.value }}</span> </li> </ul> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { list:[ { value:'html', active:false }, { value:'css', active:false }, { value:"javascript", active:true } ] }; var vm = new Vue({ el: "#app", data() { return obj; } });
虽然以上代码不会报错,但这会造成很大的渲染开销,因为v-for
优先级高于v-if
,这就造成每次执行v-if
指令时总要先执行v-for
遍历一遍数据。你可以点击此处具体示例查看。
遇到这种情况,我们可以使用计算属性。如:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>v-if和v-for</title> </head> <body> <div id="app"> <ul v-if="newList"> <li v-for="(item,index) in newList" v-bind:key="index"> <span>{{ item.value }}</span> </li> </ul> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { list: [ { value: "html", active: false }, { value: "css", active: false }, { value: "javascript", active: true } ] }; var vm = new Vue({ el: "#app", //先过滤一次数组 computed: { newList: function() { return this.list.filter(function(item) { return item.active; }); } }, data() { return obj; } });
如此一来,就减少了渲染开销,你可以狠狠点击这里具体示例查看。
指令的用法还远不止如此,一些指令是可以带参数的,比如v-bind:title
,在这里title
其实就是被作为参数。基本上HTML5属性都可以被用作参数。比如图片路径的src
属性,再比如超链接的href
属性,甚至事件的添加也属于参数,如v-on:click
中的click其实就是参数。来看一个示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!-- 引入vue.js开发版本 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <title>param</title> </head> <body> <div id="app"> <a v-bind:href="url">思否</a> <img :src="src" alt="美女" /> </div> <script> //这里写JavaScript代码 </script> </body> </html>
js代码:
var obj = { url: "https://segmentfault.com/", src:"http://eveningwater.com/project/imggallary/img/15.jpg" }; var vm = new Vue({ el: "#app", data() { return obj; } });
效果如图所示:
你可以点击此处具体示例查看。
v-on
指令还可以添加修饰符,v-bind
与v-on
指令还可以缩写成:
和@
。缩写对于我们在繁琐的使用指令的项目当中是一个很不错的帮助。