vue
Vue.js 构建数据驱动的web界面库。集中实现MVVM 的 VM层。容易与其他库或项目整合
通过尽可能简单的API实现相应的数据绑定和组合的视图组件
核心:相应的数据绑定系统, 数据与DOM保持同步
数据驱动的视图,普通的HTML模板中使用特殊的语法讲DOM"绑定"到底层数据
整个程序分为:
全局设计:包括全局接口,默认选项
VM实例设计: 包括接口设计(VM原型),实例初始化过程设计()
deps里存在的是各个响应数据依赖对象的引用因此可以手动改动响应数据的订阅依赖。
简介
Vue是一个类,想获取该类的实例化对象需要通过new
// model
var data = {
info: 'pink'
}
//vm 实例
var vm = new Vue({
el: '#app',
data: data
});
整个实例初始化过程中,最主要的就是把数据(Model) 和视图(View)建立联系
通过observer对data进行监听,并且提供订阅某个数据项的变化的能力
把template解析成一段document fragment,然后解析成其中的directive,得到每一个directive所依赖的数据项及更新方法
通过watcher把上述两部分结合起来,把directive中的数据依赖订阅在对应数据结构的observer,当数据变化的时候,就会触发observer,进而触发相关依赖对应的视图更新方法,最后达到模板原本的关联效果。
整个VM实例核心,通过observer,directive(parser),watcher。
Vue生命周期
module.exports = {
template: require('list.html'),
data: function(){
return {items:[{"id":1,"name":"hello11"},{"id":2,"name":"hello22"}]};
},
//在实例开始初始化时同步调用。此时数据观测、事件和 watcher 都尚未初始化
init:function(){
console.log("init..");
},
//在实例创建之后同步调用。此时实例已经结束解析选项,这意味着已建立:数据绑定,计算属性,方法,watcher/事件回调。但是还没有开始 DOM 编译,$el 还不存在。
created:function(){
console.log("created..");
},
//在编译开始前调用。
beforeCompile:function(){
console.log("beforeCompile..");
},
//在编译结束后调用。此时所有的指令已生效,因而数据的变化将触发 DOM 更新。但是不担保 $el 已插入文档。
compiled:function(){
console.log("compiled..");
},
//在编译结束和 $el 第一次插入文档之后调用,如在第一次 attached 钩子之后调用。注意必须是由 Vue 插入(如 vm.$appendTo() 等方法或指令更新)才触发 ready 钩子。
ready: function () {
console.log("ready..");
},
//在 vm.$el 插入 DOM 时调用。必须是由指令或实例方法(如 $appendTo())插入,直接操作 vm.$el 不会 触发这个钩子。
attached:function(){
console.log("attached..");
},
//在 vm.$el 从 DOM 中删除时调用。必须是由指令或实例方法删除,直接操作 vm.$el 不会 触发这个钩子。
detached:function(){
console.log("detached..");
},
//在开始销毁实例时调用。此时实例仍然有功能。
beforeDestroy:function(){
console.log("beforeDestroy..");
},
//在实例被销毁之后调用。此时所有的绑定和实例的指令已经解绑,所有的子实例也已经被销毁。如果有离开过渡,destroyed 钩子在过渡完成之后调用。
destroyed:function(){
console.log("destroyed..");
}
};
选择器
实例化参数中配置项中,el指代选择器,表示该实例化对象对应的容器元素
选择器和jQuery中一样的选择器,如果有多个的时候,只会选择第一个。
var vmzf = new Vue({
el: '.app',
data: data
});
数据绑定
对实例化对象绑定数据,通过data属性绑定,也是就data是一个js对象。
data中的属性与vue中的属性是同步的,不论值类型的数据,还是引用类型的数据,都是同一个。(数据绑定现象)
当实例化一个Vue构造函数,会执行Vue的init方法,在init方法中主要执行了三部分内容:
初始化环境变量
处理Vue组件数据
解析挂载组件
实现一个观察者-消费者(订阅者)模式来实现数据却动视图,通过设定对象属性的seter/getter方法来监听数据的变化,而每个属性的setter方法就是一个观察着,当属性变化将会向订阅者发送消息,从而驱动视图更新。
构建一个watcher最重要的是expOrFN和cb两个参数,cb是订阅者收到消息后需要执行的回调。一般来说这个回调都是视图指令更新的方法,从而达到视图的更新。
订阅回调也可以是一个和任何无关的纯函数。一个订阅者最重要的是要知道订阅了什么,watcher分析expOrFn的getter方法,从而间接的获得订阅的对象属性。
var data = {
info: 'pink'
}
var vmzf = new Vue({
el: '.app',
data: data
});
console.log( data.info === vmzf.info ); //true
VUe中的视图的更新其实就是指令的更新,为了做到数据驱动视图更新,需要注册一个订阅者订阅数据的变化,通过回调来进行指令更新。
path解析
path解析器的状态机
Vue.js是通过状态机管理来实现对路径的解析
状态机表是否由数字常量组成,解析更准确的同时效率也会更高。
插值
将数据同步到view(页面)
使用: {{ key }}
dom 和属性都都可以插入
<div id="app">
<span data-id="{{id}}" style="{{styles}}">{{msg}}</span>
</div>
单次插入
将数据插入页面中,而不能再被修改,或者重新插入新值
使用: {{*key}}
<div class="app">
{{*msg}}
</div>
过滤HTML标签
将数据中的html标签渲染到页面中
使用:{{{key}}}
<div id="app">{{{msg}}}</div>
var data = {
msg: 'success<strong>!</strong>'
}
var vm = Vue({
el: '#app',
data: data
});
过滤器
过滤器filter直接对插值使用
使用:{{ key | filter }}
<div id="app">
// 美元符号
<span>{{ msg | currency }}</span>
// 转大写
<span>{{ msg | uppercase }}</span>
// 首字母大写
<span>{{ msg | capitalize }}</span>
</div>
动态插值
在插入的过程中,动态对值进行修改
插入到页面中提前执行一遍
使用:
computed: {
key: function () {
reutrn newKey;
}
}
function 是在当前vue实例对象上执行,通过this可以访问到vue实例对象上的属性和方法。
computed: {
txt: function () {
return this.txt = 'pink';
}
}
数据双向绑定
v-model 当视图中一些操作会修改vue中的数据,同样, vue中的数据被修改会映射到视图中。
使用:html标签属性添加v-model, 属性值为vue绑定数据中的数据。
<div id="app">
<input type="text" name="" v-model="msg" value="" />
<span>{{msg | uppercase}}</span>
</div>
class对象绑定
使用:v-bind:class="{className: Bollean}"
如果class绑定的数据值true,className会被添加上,否则删除。
<style type="text/css">
.pink {
color: pink;
}
.bgColor {
background: tan;
}
</style>
<div class="app" v-bind:class="{pink: color, bgColor: bgColor}">{{txt}}</div>
<script>
var data = {
txt: 'pinkTan',
color: true,
bgColor: true
}
var view = new Vue({
el: '.app',
data: data,
});
</script>
class数组绑定
使用:v-bind:class="[data.property1, data.property2]"
<style type="text/css">
.pink {
color: pink;
}
.bgColor {
background: tan;
}
</style>
<div class="app" v-bind:class="[color, bgColor]">{{txt}}</div>
<script>
var data = {
txt: 'pinkTan',
color: 'pink',
bgColor: 'bgColor'
}
var view = new Vue({
el: '.app',
data: data,
});
</script>
样式的对象绑定
使用:v-bind:style="{key:value}"
<div class="app" v-bind:style="{ color: pink, background: tan }">{{txt}}</div>
<script>
var data = {
txt: 'pinkTan',
pink: 'pink',
tan: 'tan'
}
var view = new Vue({
el: '.app',
data: data,
});
</script>
样式的数组绑定
使用:v-bind: style="[style1, style2]"
<div class="app" v-bind:style="[line, color]">{{ txt }}</div>
<script>
var data = {
txt: 'pinkTan',
line: {
lineHeight: '30px',
height: '30px'
},
color: {
color: 'pink',
background: 'cyan'
}
}
var view = new Vue({
el: '.app',
data: data,
});
</script>
vue模板指令
指令是模板中出现的特殊标记,让处理模板的库知道需要对这里的DOM元素进行一些对应的处理
v-text="msg"
前缀是默认的 v-。指令的 ID 是 text,表达式是 msg。
指令告诉 Vue.js, 当 Vue 实例的msg属性改变时,更新该 div 元素的 textContent。
条件判断
v-if
v-else
<div class="app" v-bind:style="[color]">
<span v-if="isShow">|</span>
<span v-else>&</span>
<span>{{msg}}</span>
</div>
<script type="text/javascript">
var data = {
msg: 'pinkTan',
isShow: false,
color: {
color: 'pink',
background: 'tan'
}
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
多条件判断
使用:
<template v-if="key">
// 判断执行体
</tepmlate>
// 自定义标签template
<div class="app" v-bind:style="[color]">
<template v-if="isShow">
<span>|</span>
</template>
<template v-else>
<span>&</span>
</template>
<span>{{msg}}</span>
</div>
<script type="text/javascript">
var data = {
msg: 'pinkTan',
isShow: false,
color: {
color: 'pink',
background: 'tan'
}
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
显示隐藏
v-show="key"
如果key是true那么该元素显示,否则隐藏该元素
<div class="app" v-bind:style="[color]">
<span v-show="isShow">|</span>
<span>{{ msg }}</span>
</div>
<script type="text/javascript">
var data = {
msg: 'pinkTan',
isShow: false,
color: {
color: 'pink',
background: 'tan'
}
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
循环模板
v-for="item in msg"
item是msg中的成员
<ul class="app">
<li v-for="item in msg" v-bind:style="{color: item.color}">{{ item.lisTxt }}</li>
</ul>
<script>
var data = {
// msg: ['pink', 'cyan', 'tan', 'black', 'khaki'],
msg: [
{
lisTxt: 'pink',
color: 'pink'
},
{
lisTxt: 'cyan',
color: 'cyan'
},
{
lisTxt: 'tan',
color: 'tan'
},
{
lisTxt: 'black',
color: 'black'
},
{
lisTxt: 'khaki',
color: 'khaki'
}
]
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
多循环模板
使用:
<template v-for="itme in msg">
// 循环体
</template>
<ul class="app">
<template v-for="item in msg">
<li v-bind:style="{color: item.color}">{{ item.lisTxt }}</li>
</template>
</ul>
<script>
var data = {
// msg: ['pink', 'cyan', 'tan', 'black', 'khaki'],
msg: [
{
lisTxt: 'pink',
color: 'pink'
},
{
lisTxt: 'cyan',
color: 'cyan'
},
{
lisTxt: 'tan',
color: 'tan'
},
{
lisTxt: 'black',
color: 'black'
},
{
lisTxt: 'khaki',
color: 'khaki'
}
]
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
表单中数据绑定
表单操作,输入一些数据,如何将这些数据映射到js。通过v-model指令,来把数据发送给后台。
原理上是对这些表单元素在vue中绑定了一些事件来实现。
多选
v-model要绑定不同的值
<div class="app">
<input type="checkbox" v-model="size.size30" name="" id="" />中
<input type="checkbox" v-model="size.size20" name="" id="" />英
<span>{{ size| json }}</span>
</div>
<script type="text/javascript">
var data = {
size: {
size30: true,
size20: false
}
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
单选
v-model要绑定同一个值
value指定不同的值
<div class="app">
<label for="nan">男</label>
<input type="radio" name="" id="nan" v-model="sex" value="nan" />
<label for="nv">女</label>
<input type="radio" name="" id="nv" v-model="sex" value="nv" />
<span>{{sex}}</span>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '.app',
data: data
});
var data = {
msg: '',
sex: 'nv'
}
</script>
下拉框
select上面添加上一个v-model属性,即可实现下拉框的双向绑定
multiple,多选
<div class="app">
<select name="" v-model="msg" multiple="multiple">
<option selected="selected">德国</option>
<option>法国</option>
<option>葡萄牙</option>
<option>意大利</option>
</select>
<span>{{ msg }}</span>
</div>
<script type="text/javascript">
var data = {
msg: ''
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
节流&延迟
debounce 表示为双向绑定的数据进行节流处理,输入完一段时间处理
lazy表示表单失去焦点时候处理数据
<div class="app">
<input type="text" v-model="msg" debounce="1000" lazy name="" id="" value="" />--
<input type="text" v-model="msg" lazy name="" id="" value="" />
{{msg}}
</div>
自定义指令
是将传递的数据映射到DOM的行为
调用自定义指令:直接对DOM元素上添加指令名称。注意:指令前面需要加v-,对指令传递数据赋值使用=
例如:v-pirce-directive="msg";
directive 约定速成加上,表示自定义指令,不要使用驼峰式命名。
需要通过Vue.directive(); 方法实现自定义指令注册完成。
参数有两个
表示指令的名称:注意指令的名称不能有v-,注意:指令名称不能存在大写字母,字母间只能添加-
表示指令的主体,描述这个指令
This指向的是当前自定义指令实例化对象
指令创建完得到一个指令对象,那么指令对象中有个el属性,表示的调用该指令的dom元素
<div class="app">
<input type="text" v-model="msg" />
<span v-price-directive="msg"></span>
</div>
<script src="vue1.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 自定义指令
// directive(id,options)
// options 三个函数 : bind, update, unbind
Vue.directive('price-directive',{
// 绑定方法,为元素绑定指令时候执行
bind: function () {
// 应用: 有时候绑定一个指令需要执行大量业务逻辑,此时将这些业务逻辑放在bind中执行。这样update的时候,不会重复执行。 只会执行一次。
console.log(this); // directive 实例化对象
},
// 内容更新的时候调用, 这个内容指的是传递的内容msg,msg改动时即使input输入时。
// 指令内容更新调用的方法
// val 表示当前存在内容msg的值
// oldVal 表示前一个内容msg的值,第一次调用时,不存在,是undefined
update: function ( val,oldVal ) {
console.log( val, oldVal );
this.el.innerHTML = val;
},
// 对元素解除绑定 指令时执行.
unbind: function () {
console.log(123);
}
});
var data = {
msg: 123
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
例子:
<div class="app">
<label for="userName">用户名</label>
<input type="text" v-model="userName" name="userName" id="userName" value="" />
<span v-username-directive="userName">用户名4-8位</span>
</div>
<script src="vue1.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var userName = Vue.directive('username-directive', {
// update
update: function ( val,oldVal ) {
// 四到八位
// 第二个条件:判断第一次执行该方法:特点:oldValue不存在,并且value值是个空的
if ( /^\w{4,8}$/.test(val) || ( !val && !oldVal ) ) {
// 内容正确
this.el.innerHTML = '';
} else {
this.el.innerHTML = '格式错误';
}
}
});
var data = {
userName: ''
}
var vmUser = new Vue({
el: '.app',
data: data
});
</script>
自定义过滤器
通过Vue.filter(); 实现自定义过滤器
接收参数:
过滤器名称
过滤函数 - 它有一个参数,表示被处理的数据
它的this指向的是vue实例化对象,因此可以在该函数中访问到该vue实例化对象中的属性和方法
调用:
直接在数据后面添加 | 以及过滤器名称
<div class="app" id="app">
<label for="price">输入价格</label>
<input type="text" name="" v-model="price" id="price" value="" />
<span>{{ price | showPrice priceName }}</span>
</div>
<script src="vue1.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
Vue.filter('showPrice', function ( val,priceName ) {
return priceName + '$' + (+val).toFixed(2);
});
var data = {
price: '',
priceName: '输入的价格为:'
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
过滤器参数
在过滤器后面定义的数据即是将要被传递到过滤器函数中的参数
<span>{{ price | showPrice priceName }}</span>
<script type="text/javascript">
// priceName 参数后面获取
Vue.filter('showPrice', function ( val,priceName ) {
return priceName + '$' + (+val).toFixed(2);
});
var data = {
price: '',
priceName: '输入的价格为:'
}
var vm = new Vue({
el: '.app',
data: data
});
</script>
<div class="login">
用户名:<input type="text" v-model="msg" />
<ul v-show="checkNum">
<li v-for="item in email | filterBy dealNum"> {{ msg | removeEmail }}{{ item }} </li>
</ul>
</div>
<script type="text/javascript">
// v-for emial 添加自定指令
var removeEmail = Vue.filter('removeEmail', function ( val ) {
// @qq.com
return val.replace(/@.*/,'');
});
var data = {
msg: '',
email: [
'@qq.com',
'@gmail.com',
'@129.com',
'@189.com',
'@sina.com'
]
}
// login Vue 模块
var vmLogin = new Vue({
el: '.login',
data: data,
// 动态数据
computed: {
checkNum: function () {
// return this.msg ? true : false;
// return this.msg && this.msg.indexOf('@') < 0;
return this.msg;
},
dealNum: function () {
// 123@qq => 123 获取 @qq
// 第一步获取@位置
var idx = this.msg.indexOf('@');
if ( idx >= 0 ) {
return this.msg.slice(idx);
}
return '';
}
}
});
</script>
Events
绑定
v-on实现事件的绑定
<button v-on:click="getMsg">获取值</button>
注册
在vue类的参数中的methods属性中添加事件回调函数
它的this指向的是vue实例化对象
参数是事件对象
按键修饰符enter、tab、delete、esc、space、up、down、left、right
<div class="app">
<button v-on:click="getMsg">获取值</button>
<input type="text" v-model="msg" name="" id="" value="" />
<span>{{msg}}</span>
</div>
<script src="vue1.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var data = {
msg: ''
}
var vmTxt = new Vue({
el: '.app',
data: data,
methods: {
getMsg: function ( ev ) {
alert(this.msg);
}
}
});
</script>
事件参数的传递
在DOM上注册事件,在事件名称后加一对圆括号,括号中传递的参数。
events事件对象是:$event
<div class="app">
<button v-on:click="getMsg($event,msg,'嘻嘻哈哈')">获取值</button>
<input type="text" v-model="msg" name="" id="" value="" />
<span>{{msg}}</span>
</div>
<script src="vue1.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var data = {
msg: ''
}
var vmTxt = new Vue({
el: '.app',
data: data,
methods: {
getMsg: function ( ev, msg, info ) {
console.log( ev,msg,info );
}
}
});
</script>
过渡
vue的过渡动画
transition="animation"
在css上定义预定义类
animation-transition
animation-enter
animation-leave
.animation-transition {
transition: all 1s;
width: 100px;
height: 300px;
}
.animation-enter, .animation-leave {
width: 0;
height: 0;
}
组件
vue中的组件,一组可以重复利用的DOM元素(自定义的元素) -> 通常是一个自定义元素 (模板)
使用组件两部分:
定义组件
注册组件
通过template属性为组件添加模板
通过data属性为组件绑定数据
与Vue实例化对象中data属性的区别:是一个函数,需要将数据return 出来
组件定义
<div class="app">
<!--组件自定义元素-->
<components></components>
</div>
<script type="text/javascript">
// 定义组件 , 模板:template
var component = Vue.extend({
template: '<h1>嘻嘻哈哈</h1>'
});
// 注册组件
Vue.component('components',component);
var vmCom = new Vue({
el: '.app'
});
</script>
将组件上的数据映射到自定义模板标记上
props: ['msg']
可以对组件添加属性,将父组件中的数据传递进来,子组件需要定义props。子组件使用父组件的功能。
子组件使用父组件中的数据,在它的方法中,通过this.$parent来使用父组件中的数据。
<div class="app">
<!--组件自定义元素-->
<components msg="-info"></components>
</div>
<script type="text/javascript">
// 定义组件 , 模板:template
var component = Vue.extend({
// 将组件上的数据映射
template: '<h1>嘻嘻哈哈{{msg}}</h1>',
props: ['msg']
});
// 注册组件
Vue.component('components',component);
var vmCom = new Vue({
el: '.app'
});
</script>
动态组件
无法同时显示 多个组件
就要在视图中写入该组件对应的自定义元素。
添加属性v-bind:is="组件的名称"
实现组件之间切换
<component v-bind:is="view"></component>
// 定义组件
var Home = Vue.extend({
template: '<h1>home</h1>'
});
var List = Vue.extend({
template: '<h1>List</h1>'
});
var Product = Vue.extend({
template: '<h1>product</h1>'
});
// 实现组件绑定
Vue.component('home',Home);
Vue.component('list',List);
Vue.component('product',Product);
// 数据
var data = {
view: 'home'
}
// Meittuan实例化
var MeituanVm = new Vue({
el: '#app',
data: data
});
动态通信
v-bind: 将数据绑定到属性上
v-bind:propsname="key"
组件是一个独立的环境,如果需要事件方法绑定,写在组件内部。
父组件到子组件的通信
通过对子组件绑定属性,属性值是父组件内的数据,在子组件中通过props属性来订阅,实现父组件到子组件的通信
$broadcast
<button v-on:click="tuUpper">将h1中内容大写</button>
template: '<h1>hello{{msg}}</h1> <button v-on:click="tuUpper">将h1中内容大写</button>', // 发布事件
methods: {
// 定义事件
tuUpper: function ( ev ) {
this.msg = this.msg && this.msg.toUpperCase();
}
}
子组件收到父组件的信息
events是一个对象,每一个属性值就是一个消息名称
// 发布事件 // 子组件到父组件的通信
this.$dispatch('appMsg', this.msg);
events: {
// 定义事件
appMsg: function ( msg ) {
console.log(msg);
}
}
可以通过消息系统实现,在父组件中订阅消息(events属性内),在子组件中发布这条消息,this.$dispatch('appMsg', 'hello');
<div class="app">
<input type="text" v-model="inp" />
<span>{{inp}}</span>
<!--组件自定义元素-->
<!--<components msg="-info"></components>-->
<components v-bind:msg="inp"></components>
</div>
<script type="text/javascript">
// 定义组件 , 模板:template
var component = Vue.extend({
// 将组件上的数据映射到组件上
props: ['msg'],
template: '<h1>hello{{msg}}</h1> <button v-on:click="tuUpper">将h1中内容大写</button>', // 发布事件
methods: {
// 定义事件
tuUpper: function ( ev ) {
this.msg = this.msg && this.msg.toUpperCase();
// 发布事件
this.$dispatch('appMsg', this.msg);
}
}
});
// 注册组件
Vue.component('components',component);
var vmCom = new Vue({
el: '.app',
data: {
inp: ''
},
events: {
// 定义事件
appMsg: function ( msg ) {
console.log(msg);
}
}
});
</script>
组件添加数据
$set
需要在组件data中先设置为默认值
在组件中为组件绑定数据不可以通过this.msg这种方式来添加绑定的数据,必须通过$set方法添加绑定的数据
this.$set('list', reslut.list);
动态属性
在vue中如果属性需要动态渲染使用 v-bind 指令
img,请求图片数据,有时候会 {{}} 解析不成功,需要使用动态属性
<img v-bind:src="'img/icon/' + item.url" alt="">
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。