Advanced Vue.js Features from the Ground Up
Introduction
Agenda
- Intro
- Fundamentals: Reactivity
- Fundamentals: Writing Plugins
- Fundamentals: Render Functions
- State Management
- Routing
- Form Validation
- Component Patterns
Reactivity
Introducing Reactivity
许多人对于响应式编程这个术语有些迷惑。有的人可能认为仅仅代表了Rx.js这个库。在Vue中,响应式意味着当状态改变时,会影响整个系统随之改变,也可以特指当数据改变时,DOM元素随之改变。
1 | // 首先定义一个简单的变量 |
此时我们需要的是一个类似Excel表格的东西,当单元格的一项改变后,另一个单元格依靠公式自动计算出新的值,用代码表达的话,类似如下:
1 | onAChanged(() => { |
接下来,我们来看一个更贴合前端的需求
1 | <span class="cell b1"></span> |
- 以下是一个简单的命令式代码
1 | document |
- 我们也许可以更加声明式
1 | onStateChanged(() => { |
- 当我们把与DOM交互部分抽离出去的时候,我们就实现了一个简单的响应式框架
1 | <span class="cell b1"> |
1 | onStateChanged(() => { // 更新状态 |
1 | let update |
- In React
1 | onStateChanged(() => { |
在react中,强制要求更改状态时要手动调用setState方法,但是在Vue中,我们可以直接操作state
- In Vue
1 | autorun(() => { |
- This is the basic from of the dependency tracking systems as seen in Knockout.js, Meteor Tracker, Vue.js and MobX
Challenge: Getters and Setters
Exercise: Mini Data Observer
Goal: implement observer() and autorun() which triggers re-computation when object is mutated
getter and setter
1 | function convert(obj) { |
Challenge: Dependency Tracker
solution
1 | // a class representing a dependency |
Challenge: Mini Observer
mini observer
1 | // This is a greatly simplified version of the dependency tracking |
Writing Plugins
Introducing Writing Plugins
1 | function (Vue, options) { |
1 | Vue.use(plugin) |
1 | Vue.mixin(options) |
Challenge: Writing a Simple Plugin
solution
1 | const RulesPlugin = { |
Render Functions
Introducing Render Functions
Initial Render
Template
- -> (compiled into) Render Function
- -> (returns) Virtual DOM
- -> (generates) Actual DOM
Subsequent Updates
Render Function
- -> (returns) New Virtual DOM
- -> (diffed againest Old Virtual DOM) DOM Updates
- -> (applied to) Actual DOM
Virtual DOM
Actual DOM
1
document.createElement('div')
Virtual DOM
1
vm.$createElement('div')
Actual DOM
"[Object HTMLDivElement]"
- Browser Native Object(expensive)
Virtual DOM
{ tag: 'div', data: { attrs: {}, ... }, children: [] }
- Plain JavaScript Object(cheap)
Virtual DOM
- (Essentially) A lightweight JavaScript data format to represent what the actual DOM should look like at a given point in time
- Decouples rendering logic from the actual DOM - enables rendering capabilities in non-browser environments, e.g. server-side and native mobile rendering
Render Function:
- A function that returns Virtual DOM
Template -> [ Compiler ] -> Render Function
Putting Everything Together
JSX vs. Templates
- JSX与template都是声明数据与DOM之间关系的方式。Template语法更加静态,JSX更加动态。由于Template更加静态,可以在编译阶段做出许多假设来进行优化,但是实现功能时的灵活性也相对较差。JSX更加动态,所以编译时很难做出预判,但是对应的书写起来更加灵活。
Render Function API
Render Function API
1
2
3
4
5export default {
render (h) { // h -> hyper script, 类似浏览器中document.createElement
return h('div', {}, [...])
}
}The “h” function
1
2
3
4
5
6
7
8h('div', 'some text')
h('div', { class: 'foo' }, 'some text')
h('div', { ... }, [
'some text',
h('span', 'bar')
])h can directly render a component
1
2
3
4
5import MyComponent from '...'
h(MyComponent, {
props: {...}
})
Challenge: Dyamically Render Tags
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Challenge: Dynamic Render Components
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Challenge: Higher-Order Components
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
State Management
Introducing State Mangement
- Agenda
- Shared objects as stores
- Shared Vue instances as store
- Abstracting the mutations API
- Bonus: using a more functional interface
Challenge: Passing Props
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Challenge: Shared Object
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Challenge: Shared Instance
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Challenge: Mutation
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Challenge: Functional
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Routing
- Agenda
- The simplest router(hashchange +
<component :is>
) - Extracting a route table
- URL matching with
path-to-regexp
- The simplest router(hashchange +
Challenge: Basic Hash Router
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Challenge: Route Table
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Path to Regular Expressions
Challenge: Dynamic Routes
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Form Validation
Markup-based vs. Model-based
- Different Validation Plugin Styles
- Markup-based(vee-validate)
- Model-based(vuelidate)
Validation Library
solution
1 | <script src="../node_modules/vue/dist/vue.js"></script> |
Internationalization
Internationalization Apporaches
simple-i18n.html
1 | <script src="../node_modules/vue/dist/vue.js"></script> |