Vue.js基础入门
概述
Vue应用,一切以new Vue()
创建根VUE实例开始,给予一个容器,实现双向绑定响应式单页面应用。
示例
//全局模板
Vue.component("tmp",{
template:`<div><button v-on:click="add" {{text}}</button></div>`,
data:function(){
return {text:0};
},
methods:{
add:function(){
this.text++;
}
}
})
var app = new Vue({
el:"#app",
})
//关键词
var app = new Vue({
el:"",
data:"" || fn,
computed:fn,
methods:{fn:fn()},
props:[""],
components:{comp1:{...}},
watch:,
mounted:{fn},
//......
})
不要在选项属性或回调上使用箭头函数,(this)会报错
生命周期钩子
了解生命周期(Vue中文官网)很重要,深入理解VUE的工作流程和原理,以及触发事件。常用钩子:created
实例创建且data/computed/watch完成、mounted
渲染挂载DOM、updated
状态更新后DOM渲染、destroyed
实例销毁后
如果需要整个视图渲染后执行,使用
this.$nextTick
updated
虚拟DOM已经重新渲染,避免更改状态,而只是执行依赖DOM的操作;如需根据数据更新状态,可以使用computed
或watch
代替;
常用指令及修饰符
指令 | 语法 | 修饰符 | 描述 |
---|---|---|---|
v-text | <span v-text="msg"> | 插入textContext,等同于<span>{{msg}}</span> | |
v-html | 插入html,其内部HTML不会预编译scoped 样式,可以使用全局样式 | ||
v-bind | : | 动态绑定 | |
v-if、v-else-if、v-else | “真正”条件渲染,事件和子组件会销毁和重构,考虑初次渲染开销 | ||
v-show | “假性”条件渲染,只是切换display 属性,减少频繁切换的开销 | ||
v-model | .lazy .number .trim | 仅input/select/textarea表单输入,和components自定义 | |
v-for | v-for=“(item,index) in Arr/Obj/Num/Str”,或(val,name,index) in Object | 迭代遍历,比v-if 拥有更高优先级 | |
v-on | v-on:event="fn" 、@event="fn($event)" | .prevent .stop .once .self native .left .right .middle .passive .capture | 监听事件,动态绑定事件@[event_name]="fn" |
v-slot | #slot_name="prop_name" | 仅用于<template> 和组件 | |
v-pre | 跳过元素及其子元素的编译过程,显示原始 Mustache 标签,即双花括号以及内容 | ||
v-once | 只渲染一次,之后静态显示 | ||
v-cloak | css:[v-cloak]{display:none} HTML:<div v-cloak>{{msg}}</div> | 直到关联实例结束编译后移除v-cloak,如示例:编译之前不可见 |
详解
- 插值
- 文本:Mustache语句“{{}}”,插入纯字符串;
- HTML:
v-html
,插入html忽略其内部的Vue语句,且导致XSS攻击; - HTML元素特性:
v-bind:属性="值"
,动态绑定属性; - JS表达式:只能执行单个表达式,而不是语句,可以执行封装函数;
- 动态绑定 v-bind
- 绑定样式 CLASS
对象语法:v-bind:class="{className:isTrue}"
进行判断,如果isTrue为真,则className在classList中;可以放入data/computed属性中;可以同时存在静态class
属性;
数组语法::class="[data1,data2]"
传入data数据;三元法:class="[..?..:..]"
;嵌套对象语法:class=“[{..:..},data1]”
;
组件上使用,会加到根元素上;
- 绑定内联样式 STYLE
对象语法:v-bind:style="{color:red;'font-size':fontSize+'px';}"
,可以使用data/computed数据对象;
数组语法::style="[data1,data2]"
vue.js自动响应不同浏览器加前缀;
- 条件渲染 v-if v-show
- v-if和v-show的不同点:
v-show
会初始渲染进DOM,以display
属性切换显/隐,不支持标签<template>
;v-if
v-else-if
v-else
依条件渲染,不增加初始渲染开销;
多条HTML标签时,可以包裹在
<template>
标签里,其不会渲染进HTML;用KEY管理避免高度复用,因为v-if渲染机制不是从头开始,而是复用已有元素,例如避免表单验证输入框内容不清空;
- 列表渲染 v-for
动态渲染,必须加key
属性,以识别节点;同上v-if支持<template>
;
//动态渲染每项
<div v-for="item in items" :key="item.id"></div>
//多种渲染方式
//数组,可以用“of”,**更接近迭代器语法**
<div v-for="item in items"></div>
<div v-for="(item index) of items"></div>
//对象,键值对
<div v-for="value in Object"></div>
<div v-for="(value key) in Object"></div>
<div v-for="(value key index) in Object"></div>
注意:
v-for
和v-if
一起用时,v-for
有更高优先级<li v-for="item of items" v-if="isYes"></li>
==>遍历后每项按条件决定是否渲染;
<ul v-if="isYes"><li v-for="item in items"></li></ul>
==>条件判断后是否遍历
key是VUE识别节点的通用机制
- 事件监听 v-on
语法:v-on:event.ops="fn"
原始的DOM事件以
$event
参数传入
- 事件修饰符(可串联,按顺序执行)
–.prevent
= event.preventDefault()阻止默认行为
–.stop
= event.stopPropagation()阻止冒泡
–.captrue
= 捕获开启
–.self
= 自身绑定事件由自身触发
–.once
= 只触发一次(用于自定义组件)
–.passive
= 不阻止默认行为 - 按键修饰符(
v-on:event.keyCodes.112="fn"
)
–.enter
.tab
.delete
.esc
.space
.up
.down
.left
.right
–.ctrl
.alt
.shift
.meta
(特殊组合键,串联)
– 自定义映射:Vue.config.keyCodes.f1=112
–.exact
仅当此按键时触发 - 鼠标修饰符
–.left
.right
.middle
- 表单输入绑定 v-model
作用于input
textarea
select
,实例中data
值会覆盖HTML的初始值,
表单输入时触发input
事件,所有的动态绑定需定义在data
特性里。
中文输入法的动态输入,可以监听表单控件的
change
事件
-
修饰符
v-model
每次input事件触发
.lazy
每次change事件触发.number
转为数字类型trim
过滤首尾空格 -
自定义组件上使用
v-model
的问题:内部<template>
的表单控件需手动绑定,才能实现响应式:
* Vue作用域限制,需要手动实现内外通信;父->子:父+[props]
;子->父:子+$emit
;弟->兄:全局new Event = new Vue()
适配器+$emit
//绑定自定义事件,传递数据
计算属性
在插入值中使用函数处理数组过于复杂,可通过计算属性得到;如果计算属性B依赖于另一个计算属性A,而A计算开销过大,所以会有缓存机制;
默认getter,可以设置setter
computed:{
//默认getter
yo:function(){return ...}
//设置setter
ho:{
get:function(){return ...},
set:function(newValue){
...
this.data = newValue;
...
}
}
},
watch:function(newVal,oldVal){
...
}
- vue二次开发包裹了数组的方法:
- 变异方法(改变原始数组):增:
push(尾)
unshift(头)
,删:pop(尾)
shift(头)
,剪切:splice()
,排序:sort()
,倒置:reverse()
- 非变异方法(生成新数组): 过滤:
filter()
, 合并concat()
,截取slice()
- Vue不检测利用索引、修改长度的数组变动,
vm.items[index]=newVal
和vm.items.length=newLength
无效;
可以利用vm.$set()/Vue.set(items,index,newitem)
或vm.items.splice(index,1,items)/vm.items.splice(newLength)
改变;
或手动监听更新。- Vue不自动检测对象的属性添加或删除,使用
this.$set(this.data1,"new_key","value")
,或一次添加多个Object.assign()
或_.extend()
方法=>this.data1 = Object.assign({},this.data1,{key:value,key:value,...})
- 监听属性
观察vue实例上的数据变化另一个方法;可以执行异步函数,应用逻辑等复杂的处理;
处理对象
vue无法对根对象的属性更改,可嵌套在根对象内处理
vm.$ser/Vue.set(object,key,value)
对象增加一个键值对;- 通过
Object.assign()
或_.extend()
方法,增多个键值对(合并生成新对象后,赋值)
vm.newObject = Object.assign({},vm.oldObject,{key1:value,key2:value2});
组件
- 声明
new Vue()
实例必须在Vue.component
组件之后; - 组件名:小写加连字符“-”;
data
特性是函数,可以返回独立的数据拷贝;- 全局注册
Vue.component
和局部注册vm=new Vue({components:{...}})
的作用域;(通信问题) - 组件内模版内容只能在一个根元素下;模版可以被
<template id="#">
封装后引用;
组件间的通信
- 父子通信:
//html,自定义属性传入数据
<user username="lsd"></user>
//javascript
Vue.component("user",{
template:`
<div>
用户:<a href=`"./user/"+ username` >@{{username}}</a>
</div>
`,
props:["username"]
})
结果:
用户:@lsd
- 子父通信
子级触发事件执行函数,生成$emit
自定义事件并传参,父级监听自定义事件后触发函数并处理数据;
//html
<div class="app">
<box></box>
</div>
//javascript
//父级
Vue.component("box",{
template:`
<div>
//关联钩子事件showE,并触发函数show_balance(),传参data
<show @showE="show_balance"></show>
<span v-if="showit">{{username}}余额:{{balance}}元</span>
</div>`,
//动态数据,独立拷贝
data:function(){
return {
username:"您的",
balance:"00.00",
showit:false
}
},
methods:{
show_balance:function(data){
this.username = data.uername;
this.balance = data.balance;
this.showit = true;
}
}
});
//子级
Vue.component("show",{
template:`
<div>
//点击事件触发on_click()函数
<button @click="on_click" type="button">显示余额</button>
</div>`,
methods:{
on_click:function(){
//点击后触发,生成自定义事件show,暴露事件
this.$emit("showE",{balance:1000,username:"lsd"})
}
}
})
//声明
new Vue({
el:".app"
})
- 平行组件的通信
重点在于新建调度器var Event = new Vue()
,绑定自定义事件Event.$emit
钩子后监听Event.$on:
;注意函数内this
的变化。
过滤器 Vue.filter()
{{Object | filterName}}
加过滤符
Vue.filter("filterName",fn(条件))
过滤处理函数
自定义指令 Vue.directive()
语法:Vue.directive("v-codeName",function(el,binding){if-elseif-else})
配置传参和修饰符:
Vue.directive("v-codeName",function(el,binding){
var val = binding.value;//?
var position = binding.modifiers;//修饰符
var info = binding.arg;//传参
})
混合 mixins
//javascript
var base = {
methods:{
show:function(){
this.visibal = true;
},
hide:function(){
this.visibal = false;
},
toggle:function(){
this.visibal = !this.visibal;
}
},
data:function(){
return {visibal : false}
}
};
Vue.component("popup",{
template:`
<div>
<button @click="toggle">popup</button>
<p v-if="visibal">yoyoyoyoyoyoy</p>
</div>
`,
//混合mixins的模版
mixins:[base],
//此处的data会覆盖mixins里的data值
data:function(){
return {visibal : true};
}
})
Vue.component("tooltip",{
template:`
<div>
<p @mouseenter="show" @mouseout="hide">popup</p>
<p v-if="visibal">yoyoyoyoyoyoy</p>
</div>
`,
mixins:[base]
})
插槽 slots
component的template
里插入slot
,html中自定义组件插入内容即可,
//html
<div slot="header">插入的内容</div>
<div slot="main">插入的内容</div>
<div slot="footer">插入的内容</div>
<template>
//name属性,一一对应
<slot name="header">默认占位信息</slot>
<slot name="main">默认占位信息</slot>
<slot name="fotter">默认占位信息</slot>
</template>
作用域:slot-scope
嵌套:函数嵌套函数,模版嵌套模版
实战–豆瓣API搜索书籍
//html
<div id="app">
<h3>豆瓣搜书</h3>
<div class="form-bar">
<form @submit.prevent="search()">
<input type="text" v-model="keyword">
<button type="submit">提交</button>
</form>
</div>
<div class="show-bar">
<div v-for="book in result.books" >
<img style="width:100px;" :src="book.images.small">
<span>{{book.title}}</span>
<span>{{book.author}}</span>
</div>
</div>
</div>
<script src="./jQuery.js"></script>
<script src="./vue.js"></script>
<script src="./main.js"></script>
//main.js
;(function(){
'use strict';
new Vue({
el:"#app",
data:{
keyword:"",
result:{}
},
methods:{
search:function(){
var it = this;
$.ajax({
url:"https://api.douban.com/v2/book/search?q=" + this.keyword,
dataType:"jsonp"
}).then(function(r){
it.result = r;
})
}
}
})
})()