我从未见过如此简洁易懂的Vue教程

我从未见过如此简洁易懂的Vue教程

这是一篇长文,按照我自己的逻辑重新整理一下,包含所有Vue的基础知识点。

但是我更建议你先简略的阅读官方的文档,因为本文具有一定的阅读门槛,同时我也竭尽所能把这门槛降到最低,同样你也可以把本文作为快速回忆教程。

发挥100%的专注力,调动体内所有的热情,你将做到很多令人惊叹的事情

什么是MVVM ?

对比以前的mvc或者mvp,就是把C或者p替换成vm

vm就是上图,请仔细看一些细节,vm监听DOM,当数据改变的时候,vm会去自动更新视图。

面向未来的组件系统

实现了一些未来的w3c规范(暂不赘述)

  • Web 组件规范
  • Slot API

根 vue 实例

let viewModel = new Vue({
    // 包含数据、模板、挂载元素、方法、生命周期钩子等选项
})

Hello Wrold 例子

<!-- 这是我们的 View -->
<div id="app">
  Hello {{ name }}!
</div>
// 这是我们的 Model
var model = {
  name: 'Vue.js'
}

// 创建一个 Vue 实例或 "viewModel"
// 它连接 View 与 Model
var viewModel = new Vue({
  el: '#app',
  data: model
})

组件 Component 构造器

vue.extend()返回的只是一个构造器,我们需要通过vue.extend()的返回值和new关键字创建实例。

当我们注册为组件的时候,内部就已经帮我们创建好了实例。

Tip: 如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。

<div id="app">
  <v-footer></v-footer> <!-- 加一个v前缀,跟原生的footer标签区别开来 -->
</div>
let Footer = vue.extend({
    template: '<div>我是页脚组件</div>'
})

// 注册为全局组件
Vue.component('v-footer', MyComponent)

// 创建根实例
new Vue({
  el: '#app'
})

生命周期


上图的就是ViewModel的生命周期,仔细的看其实并不难。目前先了解一下。

在传统软件工程中,特别是QT类桌面端软件,都有软件的生命周期,还有比如Android的生命周期,React的生命周期。

目前的前端趋势正在向此方面靠近。

流程大致像这样

created()->beforeCompile()->compiled()->ready()

->attached()->detached()->beforeDestroy()->destroyed()   

更详细的介绍,请点这里查看API文档

绑定

简单的理解就是模板字符串功能,放心的在任何你想用的地方去用,假如错了vue会给你提示。

定界符都是可以修改的

// 模板定界符
Vue.config.delimiters = ['{{', '}}']

// html模板定界符
Vue.config.unsafeDelimiters = ["{{{", "}}}"]

数据的绑定

<span>消息: {{ msg }}</span>  <!-- 同步更新js里面的数据 -->

<span>他将永不会改变: {{* msg }}</span>  <!-- 第一次插入之后就不更新了 -->

<div>{{{ raw_html }}}</div> <!-- 插入原生的 html -->

<div id="item-{{ id }}"></div> <!-- 放在id中 -->


表达的绑定

不可使用,var/let关键字声明变量,也不能使用if/for流程控制。

{{ number + 1 }}   // 做简单的运算

{{ ok ? 'YES' : 'NO' }}   // 三元表达式

{{ message.split('').reverse().join('') }}   // 调用该对象上的方法 

过滤器

对数据进行相应的处理,message第一个参数filter要执行的函数

{{ message | filter }}

{{ message | filterA | filterB }} // filterB(filterA(message))

{{ message | filterA 'arg1' arg2 }} 

// arg2是一个表达式(假设是1+2) filterA(message,arg1,3)

指令

当其表达式的值改变时把某些特殊的行为应用到 DOM 上。

<p v-if="ok">Hello!</p> <!-- 根据if里面的值,确定是否编译 -->

<a v-bind:href="url"></a>  
<!-- 等于href="{{url}}" 这里 href 是参数,将元素的 href 属性传进去。
     告诉vue元素的 href 特性跟表达式 url 的值绑定 -->


<a v-on:click="doSomething"> 
<!-- v-on表示监听,传入了click参数,表示当click事件发生的时候,执行doSomething函数 -->


<a v-bind:href.literal="/a/b/c"></a>
<!-- .literal 修饰符告诉指令将它的值解析为一个字面字符串而不是一个表达式 -->

v-bind 缩写

<!-- 完整语法 -->
<a v-bind:href="url"></a>

<!-- 缩写 -->
<a :href="url"></a>
<!-- 完整语法 -->
<a v-on:click="doSomething"></a>

<!-- 缩写 -->
<a @click="doSomething"></a>

计算属性

<div id="example">
  a={{ a }}, b={{ b }}
</div>
var vm = new Vue({
  el: '#example',
  data: {
    a: 1
  },
  computed: {
    // 一个计算属性的 getter
    b: function () {
      // `this` 指向 vm 实例
      return this.a + 1
    }
  }
})

给计算属性设置setter

computed: {
    fullname: {
        get: function() {
            return this.firstName + ' ' + this.lastName
        },
        set: function() {
            let names = newValue.split(' ')
            this.firstName = names[0]
            this.lastName = names[names.length - 1]
        }
    }
}

$watch

通常更优的做法是使用computed计算属性

<div id="app">{{ fullname }}</div>
let vm = new Vue({
    data: {
        firstName: 'C',
        lastName: 'O',
        fullName: 'CO'
    }
})

vm.$watch('firstname', funciton(val){
    this.fullname = val + ' ' + this.lastName   
})

vm.$watch('lastname', funciton(val){
    this.fullname = this.firstName + ' ' + val  
})


// 等价于

let vm = new Vue({
    data: {
        firstName: 'Foo',
        lastName: 'Bar'
    },
    computed: {
        fullName: function(){
            return this.firstName + ' ' + this.lastName
        }
    }
})


Class 与 Style 绑定

vue特意增强了他们,支持对象和数组绑定

Class 对象绑定

<div class="static" :class="{ 'class-a': isA , 'class-b': isB}"></div>

data: {
    isA: true,
    isB: false
}

<div class="static" :class="classObjcet"></div>

data: {
    classObject: {
        'class-a': true
        'class-b': false
    }
}


//渲染之后

<div class="static class-a"></div>

Class 数组语法

<div :class="[classA,classB]"></div>

data: {
    classA: 'class-a'
    classB: 'class-b'
}

// 渲染为

<div class="class-a class-b"></div>


<div :class="[classA, isB? classB : '']"></div>

// 始终添加classA对应的类名,根据isB的值确认是否添加classB对应的值。

// 在1.0.19+之后,为了更明了的写法,支持数组里面嵌套对象语法

<div :class="[classA, {classB: isB, classC: isC}]"></div>

Style 对象语法

CSS 属性名可以用驼峰式(camelCase)或短横分隔命名(kebab-case),自动添加浏览器的前缀。

<div :style="{color: activeColor, fontSize: fontSize + 'px' }"></div>

data: { 
    activeColor: 'red',
    fontSize: 30
}

<div :style="styleObject"></div>

data = {
    styleObject: {
        color: 'red',
        fontSize: '13px'
    }
}

Style 数组语法

<div :style="[styleObjectA,styleObjectB]"></div>

data = {
    styleObjectA: {
        fontSize: '15px'
    }
}

条件渲染

** Tip: v-else 元素必须立即跟在 v-if 或 v-show 元素的后面——否则它不能被识别。**

v-if

<h1 v-if="ok">yes</h1>
<h1 v-else>no</h1>

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

v-show

不支持 template 元素包裹

<h1 v-show="ok">Hello!</h1>

// 在组件上不能使用 v-else
<custom-component v-show="condition"></custom-component>
<p v-show="!condition">这可能也是一个组件</p>

if 与 show 之间的战争

如果需要频繁切换 v-show 较好,如果在运行时条件不大可能改变 v-if 较好。

列表渲染

<ul id="list">
    <li v-for="item in items">
        {{ item.message }}
    </li>
</ul>


var vm = new Vue({
    el: '#list',
    data: {
        items: [
            { message: 'Foo' },
            { message: 'Bar'}
        ]
    }
}) 

通过$index可以访问索引,且在v-for块内可以访问的到其他属性。

<ul id="list">
    <li v-for="item in items">
        {{ parentMessage }} - {{ $index }} - {{ item.message }}
    </li>
</ul>


var vm = new Vue({
    el: '#list',
    data: {
        parentMessage: 'Parent',
        items: [
            {message: 'Foo'},
            {message: 'Bar'}
        ]
    }
})


为索引设置一个别名,且 1.0.17+ 之后可以使用 for of

<div v-for="(key,value) of items">
</div>


// 使用一层 template 包裹
<template v-for="item in items">
    <span>{{ item.id }}</span>
    <span>{{ item.content }}</span>
</template>

数组变动检测

以下是vue提供的一些数组上的方法,能触发视图更新。

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

替换数组

当我们使用一些不改变数组本身的方法的时候(纯函数),我们可以直接赋值给自身,虽然替换了原始的数组,但是vue不会重新渲染所有,他会去进行对比。

track-by

通过此选项设置参考特征,用特征对比,一样就进行复用

{
    items: [
        {_uid: '339a99', ... }
        {_uid: '2r9c92', ... }
    ]
}

<div v-for="item in items" track-by="_uid">
  <!-- content -->
</div>

// _uid 就说明可以复用 

track-by="$index"

这样让数据替换高效,此时DOM节点不再映射数组顺序变化,不能同步临时状态。
v-for 包含 <input>元素或者子组件,要小心使用

更新问题

vue不能检测下面数组的变化

  • 直接用索引设置元素,如 vm.items[0] = {};
  • 修改数据的长度,如 vm.items.length = 0。
(1) 解决方法
vm.items.$set(0, {})

(2) 解决方法
vm.items = []

对象v-for

<ul id="repeat-object" class="demo">
    <li v-for="value in object">
        {{ $key }} : {{ value }}
    </li>
</ul>


<div>
  <span v-for="n in 10">{{ n }} </span>
</div>

方法与事件处理

<div id="example">
    <button @click="greet">Greet</button>
</div>

let vm = new Vue({
    el: '#example',
    data: {
        name: 'Vue.js'
    },
    methods: {
        greet: function(event) {
            alert('hello'+this.name+'!')
            console.log(event.target.tagName)
        }
    }

})

<div id="example">
    <button :click="say('hi')">Say Hi</button>
    <button :click="say('what')">Say What</button>
</div>


new Vue({
    el: '#example',
    methods: {
        say:  function(msg) {
            alert(msg)
        }
    }
})


事件修饰符

在事件处理器中经常需要调用event.preventDefaultevent.stopPropagation

// 阻止单击事件冒泡
<a @click.stop="do"></a>

// 提交事件不再重载页面
<a @submit.prevent="submit"></a>

// 修饰符可以串联
<a @click.stop.prevent="do"></a>

// 只有修饰符
<form @submit.prevent></form>

按键修饰符

  • enter
  • tab
  • delete
  • esc
  • space
  • up
  • down
  • left
  • right
<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">

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

<!-- 缩写语法 -->
<input @keyup.enter="submit">

自定义按键别名


// 可以使用 @keyup.f1

Vue.directive('on').keyCodes.f1 = 112

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 193,968评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,682评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,254评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,074评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,964评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,055评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,484评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,170评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,433评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,512评论 2 308
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,296评论 1 325
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,184评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,545评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,150评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,437评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,630评论 2 335

推荐阅读更多精彩内容

  • 1.安装 可以简单地在页面引入Vue.js作为独立版本,Vue即被注册为全局变量,可以在页面使用了。 如果希望搭建...
    Awey阅读 10,971评论 4 129
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,040评论 0 29
  • Vue 实例 属性和方法 每个 Vue 实例都会代理其 data 对象里所有的属性:var data = { a:...
    云之外阅读 2,177评论 0 6
  • 下载安装搭建环境 可以选npm安装,或者简单下载一个开发版的vue.js文件 浏览器打开加载有vue的文档时,控制...
    冥冥2017阅读 6,013评论 0 42
  • vue.js官网教程学习笔记和学习摘要 起步 安装 一个简单的方法,直接把一个vue.js引入你的HTML页面中,...
    恰皮阅读 3,346评论 2 22