表单控件绑定
最后更新于:2022-04-01 07:42:01
源码
最后更新于:2022-04-01 07:41:59
# 源码
* [vuejs](https://github.com/vuejs/vue)
* [vuex](https://github.com/vuejs/vuex)
## 插件
* [vue-router](https://github.com/vuejs/vue-router)
* [vue-strap](https://github.com/yuche/vue-strap)
## webpack
* [vue-loader](https://github.com/vuejs/vue-loader)
## 案例
* [vuejs/vue-hackernews](https://github.com/vuejs/vue-hackernews)
* [vue-cnodejs](https://github.com/shinygang/Vue-cnodejs)
VUE.JS: A (RE)INTRODUCTION
最后更新于:2022-04-01 07:41:57
## VUE.JS: A (RE)INTRODUCTION
> http://blog.evanyou.me/2015/10/25/vuejs-re-introduction/
![](http://blog.evanyou.me/images/logo.png)
`Vue.js` is a library for building web interfaces. Together with some other tools you can also call it a “framework”, although it’s more like a set of optional tools that work together really well. Now, if you’ve never heard of or used Vue before, you are probably thinking: great, yet another JavaScript framework! I get it. Turns out Vue isn’t particularly new — I first started working on its prototype almost two years ago, and the first public release was in `February 2014`. Over the time it has been evolving, and today many are using it in production.
So, what exactly does Vue offer? What makes it different? Why in the world would you want to learn about it when there are already Angular, Ember and React? This post attempts to shed some light on these question by taking you through a brief tour of Vue.js concepts, and I hope you will have your own answers after reading it.
### REACTIVITY
> Keeping the state and the view in sync is hard. Or is it?
Let’s start with the most basic task: displaying data. Suppose we have a simple object:
```
var object = {
message: 'Hello world!'
}
And a template:
<div id="example">
{{ message }}
</div>
And here’s how we bind the data and the template together with Vue:
new Vue({
el: '#example',
data: object
})
```
Looks like we just rendered a template. What should we do to update the view when the object changes? The answer is… nothing. Vue has converted the object and made it “reactive”. When you set object.message to something else, the rendered HTML updates automatically. More importantly, there’s no need to worry about calling $apply in a timeout, or calling setState(), or listening to store events, or creating framework-proprietary observables like ko.observable() or Ember.Object.create()… it just works.
Vue also provides seamless computed properties:
```
var example = new Vue({
data: {
a: 1
},
computed: {
b: function () {
return this.a + 1
}
}
})
// both a & b are proxied on the created instance.
example.a // -> 1
example.b // -> 2
example.a++
example.b // -> 3
```
The computed property b tracks a as a dependency, and is automatically kept in sync. No need to declare the dependencies yourself, because you shouldn’t have to.
In addition, POJO-based reactivity makes it trivially easy to integrate with any type of data-source or state management solutions. For example, here’s an integration that enables Vue.js components to bind to RxJS Observables with less than 30 lines of code.
### COMPONENTS
Ok the data binding is neat for small demos. What about big apps?
When it comes to structuring complex interfaces, Vue takes an approach that is very similar to React: it’s components all the way down. Let’s make our example a reusable component:
```
var Example = Vue.extend({
template: '<div>{{ message }}</div>',
data: function () {
return {
message: 'Hello Vue.js!'
}
}
})
// register it with the tag <example>
Vue.component('example', Example)
```
Now we can use the component in other templates simply as a custom element:
```
<example></example>
```
Components can contain other components, and they form a tree that represents your UI. To make them actually composable, Vue components can also:
* Define how it expects to receive data from its parent using props;
* Emit custom events to trigger actions in parent scope;
* Compose parent injected content with its own template using <slot>.
We are not going to go into the details here, but if you are interested, checkout more in the [official guide](http://vuejs.org/guide/components.html).
### MODULARITY
> It’s 2015 and we shouldn’t put everything in the global scope!
Let’s use a module bundler ([Webpack](http://webpack.github.io/) or [Browserify](http://browserify.org/)) and use ES2015. Each component can just be in its own module. Since Vue will automatically convert option objects into component constructors, we can simply export an object:
```
// ComponentA.js
export default {
template: '<div>{{ message }}</div>',
data () {
return {
message: 'Hello Vue.js!'
}
}
}
```
```
// App.js
import ComponentA from './ComponentA'
export default {
// use another component, in this scope only.
// ComponentA maps to the tag <component-a>
components: { ComponentA },
template: `
<div>
<p>Now I'm using another component.</p>
<component-a></component-a>
</div>
`
}
```
Pretty nice, huh? Wouldn’t it be even better if we can encapsulate a component’s template, styles and JavaScript logic in the same file, and getting proper syntax highlighting for each? With tools like Webpack + vue-loader or Browserify + vueify, you can:
```
<!-- MyComponent.vue -->
<!-- css -->
<style>
.message {
color: red;
}
</style>
<!-- template -->
<template>
<div class="message">{{ message }}</div>
</template>
<!-- js -->
<script>
export default {
props: ['message'],
created() {
console.log('MyComponent created!')
}
}
</script>
```
Wait a minute, did we just re-invent Web Components? But your CSS is still global!
Well, sort of, except:
* You can have style encapsulation. Just add a scoped attribute to the <style> tag. And it does not leak down to nested child components.
* Each Vue component is compiled into a JavaScript module, and doesn’t need any polyfill to work all the way down to IE9. You can also wrap it inside a real Custom Element if you want.
* ES2015 is supported by default in <script> tags.
* You can use any pre-processor you want in each language block.
* When using Webpack + vue-loader, you also get to leverage Webpack’s full power for static asset handling, because the template and styles are piped through html-loader and css-loader that can handle asset URLs as module dependencies.
So yeah, if you want you can have components that look like this:
![vue component](http://blog.evanyou.me/images/vue-component.png)
Oh, and did I mention Vue components are hot-reloadable?
![vue hot reload](http://blog.evanyou.me/images/vue-hot.gif)
### ANIMATIONS
> Can I make fancy stuff with it?
Vue ships with a built-in [transition system](http://vuejs.org/guide/transitions.html) that is very simple to use. There are many [award-winning interactive sites](https://github.com/vuejs/awesome-vue#interactive-experiences) built with it.
Vue’s reactivity system also makes it trivially simple to do efficient state-based tweening, which turns out to be quite a hassle in frameworks that use dirty-checking or Virtual DOM diffing. When you tween a piece of state at 60 frames per second, Vue accurately knows which bindings are affected, so it efficiently updates the affected bindings, and the rest of the app is unaffected. In both dirty checking and Virtual DOM diffing, changing a piece of state means the whole affected sub-tree (be it scopes or components) needs to be digested/re-rendered. Although it is usually “fast enough” in small demos, it most likely won’t be when you are triggering changes 60 times per second in a large app. Even if it manages to be fast enough, it will be draining device battery for all the wasted cycles. Check out [this talk](https://www.youtube.com/watch?v=xtqUJVqpKNo) to get a sense how much effort is needed to animate things efficiently in React. Vue apps are just optimized by default in these scenarios.
An example of state-based tweening with Vue:
[source code](http://codepen.io/yyx990803/pen/XmZNOG)
### ROUTING
> So I want to build an app, but where’s the router?
Like React, Vue itself doesn’t come with routing. But there’s the vue-router package to help you out. It supports mapping nested routes to nested components and offers fine-grained transition control. Here’s a simple example:
```
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './app.vue'
import ViewA from './view-a.vue'
import ViewB from './view-b.vue'
Vue.use(VueRouter)
const router = new VueRouter()
router.map({
'/a': { component: ViewA },
'/b': { component: ViewB }
})
router.start(App, '#app')
```
The template for app.vue:
```
<div>
<h1>This is the layout that won't change</h1>
<router-view><!-- matched component renders here --></router-view>
</div>
```
For an actual example, check out this [HackerNews Clone](https://github.com/vuejs/vue-hackernews) built with Vue.js, vue-router, Webpack and vue-loader.
### STABILITY
> A personal project? Seriously?
Yes, this is a personal project. So if you are looking for an enterprise backed dev team, Vue is probably not the one. But I’d rather look at the numbers. Vue has maintained [100% test coverage](https://codecov.io/github/vuejs/vue?branch=master) on every single commit since the 0.11 rewrite, and that will continue. GitHub issues are closed within [an average of 13 hours](http://issuestats.com/github/vuejs/vue), and there has been 1400+ of them. As of this writing, there are literally zero open and reproducible bugs.
Vue just recently [reached 1.0](http://vuejs.org/2015/10/26/1.0.0-release/), which means it’s production ready. The API is going to stay stable. For the 0.12 -> 1.0 upgrade, there is a migration build which ships with all the new features while remaining fully backwards compatible. The deprecation warnings will essentially guide users through the upgrade process. And that is going to be the case for any future breaking releases as well.
Well, I hope I’ve convinced at least some of you to take a deeper look at Vue. I believe it provides a valuable alternative to what’s out there, and I’d love to see you build some great stuff with it. Feel free to check out the [docs](http://vuejs.org/), or come hangout in the [forum](http://forum.vuejs.org/) and [gitter channel](https://gitter.im/vuejs/vue). Oh, and even if you don’t want to use Vue, you should [follow me on Twitter](https://twitter.com/youyuxi).
文章
最后更新于:2022-04-01 07:41:54
router.afterEach
最后更新于:2022-04-01 07:41:52
# `router.afterEach(hook)`
添加一个全局的后置钩子函数,该函数会在每次路由切换**成功进入激活阶段**时被调用。
注意,该函数调用时仅仅意味着切换已经被验证过了,也就是所有 `canDeactivate` 和 `canActivate` 钩子函数都成功的被断定( resolved )了,而且浏览器地址栏中的地址也已经更新。并不能保证所有的 `activate` 钩子函数都被断定了。
你可以注册多个全局的后置钩子函数,这些函数将会按照注册的顺序被同步调用。
### 参数
- `hook {Function}`
此钩子函数一个类型为[切换对象](../pipeline/hooks.html#transition-object)的参数,但是你只能访问此参数的 `to` 和 `from` 属性, 这两个属性都是路由对象。在这个后置钩子函数里**不能**调用任何切换函数。
### Example
``` js
router.afterEach(function (transition) {
console.log('成功浏览到: ' + transition.to.path)
})
```
router.beforeEach
最后更新于:2022-04-01 07:41:50
# `router.beforeEach(hook)`
添加一个全局的前置钩子函数,这个函数会在路由切换开始时调用。调用发生在整个切换流水线之前。如果此钩子函数拒绝了切换,整个切换流水线根本就不会启动。
你可以注册多个全局的前置钩子函数。这些函数会按照注册的顺序被调用。调用是异步的,后一个函数会等待前一个函数完成后才会被调用。
### 参数
- `hook {Function}`
此钩子函数一个类型为[切换对象](../pipeline/hooks.html#transition-object)的参数。
### Example
简单示例
``` js
router.beforeEach(function (transition) {
if (transition.to.path === '/forbidden') {
transition.abort()
} else {
transition.next()
}
})
```
使用 Promise 和 ES6
``` js
router.beforeEach(function ({ to, next }) {
if (to.path === '/auth-required') {
// 返回一个断定会 true 或者 false 的 Promise
return AuthService.isLoggedIn()
} else {
next()
}
})
```
router.alias
最后更新于:2022-04-01 07:41:47
# `router.alias(aliasMap)`
为路由器配置全局的别名规则。别名和重定向的区别在于,相对于重定向把 `fromPath` 替换为 `toPath` ,别名会保留 `fromPath` ,但是匹配时使用的是 `toPath` 。
例如,如果我们把 `/a` 取别名为 `/a/b/c` ,那么当我们访问 `/a` 时,浏览器地址栏中的URL会是 `/a` 。但是路由匹配是却像是在访问 `/a/b/c` 。
### 参数
- `aliasMap {Object}`
别名映射对象的格式应该为 `{ fromPath: toPath, ... }` 。路径中可以包含动态片段。
### Example
``` js
router.alias({
// 匹配 /a 时就像是匹配 /a/b/c
'/a': '/a/b/c',
// 别名可以包含动态片段
// 而且重定向片段必须匹配
'/user/:userId': '/user/profile/:userId'
})
```
router.redirect
最后更新于:2022-04-01 07:41:45
# `router.redirect(redirectMap)`
为路由器定义全局的重定向规则。全局的重定向会在匹配当前路径之前执行。如果发现需要进行重定向,原本访问的路径会被直接忽略而且不会在浏览器历史中留下记录。
### 参数
- `redirectMap: Object`
重定向映射对象的格式应该为 `{ fromPath: toPath, ... }` 。路径中可以包含动态片段。
### Example
``` js
router.redirect({
// 重定向 /a 到 /b
'/a': '/b',
// 重定向可以包含动态片段
// 而且重定向片段必须匹配
'/user/:userId': '/profile/:userId',
// 重定向任意未匹配路径到 /home
'*': '/home'
})
```
router.replace
最后更新于:2022-04-01 07:41:43
# `router.replace(path)`
和 `router.go(path)` 类似,但是并不会在浏览器历史创建一条新的纪录。
### 参数
- `path: String`
此路径为一个普通路径(也就是说没有动态片段或者全匹配片段)。路径不能以 `/` 开头,会以相对于当前路径的方式进行解析。
router.go
最后更新于:2022-04-01 07:41:41
# `router.go(path)`
导航到一个新的路由
### 参数
- `path: String | Object`
`path` 可以是一个字符串,或是包含跳转信息的对象。
当是字符串时,该路径必须为一个普通路径(也就是说没有动态片段或者全匹配片段)。路径若不是以 `/` 开头的绝对路径,会以相对于当前路径的方式进行解析。
当是对象时,可以是如下的格式:
``` js
{ path: '...' }
```
或是:
``` js
{
name: '...',
// params 和 query 可选
params: { ... },
query: { ... }
}
```
关于包含 `name` 的路径对象,参见[具名路径](../named.md).
- 当用 `path` 格式跳转到一个相对路径时,可以用 `append: true` 选项来确保该相对路径始终被添加到当前路径之后。比如:
- 从 `/a` 跳转到 `b` 时,若没有 `append: true`,则会跳转到 `b`;
- 从 `/a` 跳转到 `b` 时,若有 `append: true`,则会跳转到 `/a/b`。
- 两种格式都接受 `replace: true` 选项,使得该跳转不产生一个新的历史记录。
router.on
最后更新于:2022-04-01 07:41:38
# `router.on(path, config)`
添加一条顶级的路由配置。在内部实现时,`router.map()` 对于接收到的路由映射对象中每个键值对都调用 `router.on()` 。
### 参数
- `path: String` - 查看[路由匹配](../route.md#route-matching)
- `config: Object` - 查看[路由配置对象](map.md#route-config-object).
### 例子
``` js
router.on('/user/:userId', {
component: {
template: '<div>{{$route.params.userId}}</div>'
}
})
```
router.map
最后更新于:2022-04-01 07:41:36
# `router.map(routeMap)`
定义路由映射的主要方法。
### 参数
- `routeMap: Object`
结构体,键为路径,值为路由配置对象。对于路径匹配规则,查看[路由匹配](../route.html#route-matching).
### 路由配置对象
路由配置对象包含两个字段:
- `component`: 当路径匹配时,会渲染到顶级 `<router-view>` 的 Vue 组件。此字段的值可以是调用 `Vue.extend` 后返回的构造函数,或者普通的组件选项对象。在后一种情况下,路由会隐式调用 `Vue.extend` 。
- `subRoutes`: 嵌套的子路由映射。对于每一个 `subRoutes` 映射中的子路由对象,路由器在做匹配时会使用其路径拼接到父级路径后得到的全路径。成功匹配的组件会渲染到父级组件的 `<router-view>` 中。
### 例子
``` js
router.map({
// 组件构造函数
'/a': {
component: Vue.extend({ /* ... */ })
},
// 组件选项对象
'/b': {
component: {
template: '<p>Hello from /b</p>'
}
},
// 嵌套的路由
'/c': {
component: {
// 渲染子视图
template: '<router-view></router-view>'
},
subRoutes: {
// 当路径是 /c/d 时进行渲染
'/d': { component: { template: 'D' }},
// 当路径是 /c/e 时进行渲染
'/e': { component: { template: 'E' }}
}
}
})
```
router.stop
最后更新于:2022-04-01 07:41:34
# `router.stop()`
停止监听 `popstate` 和 `hashchange` 事件。
注意,当路由处于停止状态,`router.app` 并没有销毁,你依然可以使用 `router.go(path)` 进行跳转。你也可以不使用参数调用 `router.start()` 来重新启动路由。
router.start
最后更新于:2022-04-01 07:41:31
# `router.start(App, el)`
启动一个启用了路由的应用。创建一个 `App` 的实例并且挂载到元素 `el` 。
### 参数
- `App: Function|Object`
`App` 可以是 Vue 组件构造函数或者一个组件选项对象。如果是一个对象,路由会隐式的对其调用 `Vue.extend` 。这个组件会用来创建这个应用的根组件。
- `el: String|Element`
挂载应用的元素。可以是 CSS 选择符或者一个实际的元素。
路由实例属性
最后更新于:2022-04-01 07:41:29
# 路由器实例属性
> 这里只列出了公开属性
### `router.app`
- 类型: `Vue`
此路由器管理的根 Vue 实例。这个实例是由调用 `router.start()` 传入的 Vue 组件构造器函数创建的。
### `router.mode`
- 类型: `String`
`html5`、`hash` 或者 `abstract`。
- **`html5`**: 使用 HTML5 history API ,监听 `popstate` 事件。支持 [`saveScrollPosition`](../options.html#savescrollposition) .
- **`hash`**: 使用 `location.hash` ,监听 `hashchange` 事件。如果创建路由器时声明 `history: true` ,则在不支持 history 模式的路由器下会退化为 hash 模式。
- **`abstract`**: 不监听任何事件。如果没有 `window` 对象(例如非浏览器环境),则会自动退化到此模式。
API
最后更新于:2022-04-01 07:41:27
canReuse
最后更新于:2022-04-01 07:41:25
# `canReuse: Boolean | canReuse(transition) -> Boolean`
决定组件是否可以被重用。如果一个组件不可以重用,当前实例会被一个新的实例替换,这个新实例会经历正常的验证和激活阶段。
此路由配置参数可以是一个 Boolean 值或者一个返回同步的返回 Boolean 值的函数。**默认值为 `true` **.
### 参数
- [`transition {Transition}`](hooks.md#transition-object)
在 `canReuse` 钩子中只能访问 `transition.to` 和 `transition.from` 。
### 预期返回值
- 必须返回 Boolean 类型,其他等效的假值( Falsy values )会当作 `false` 对待。
### 详情
`canReuse` 会同步调用,而且从上至下对所有可能重用的组件都会调用。
如果组件可以重用,它的 `data` 钩子在激活阶段仍然会被调用。
canDeactivate
最后更新于:2022-04-01 07:41:22
# `canDeactivate(transition) [-> Promise | Boolean]`
在验证阶段,当一个组件将要被切出的时候被调用。
### 参数
- [`transition {Transition}`](hooks.md#transition-object)
调用 `transition.next()` 可以断定( resolve )此钩子函数。调用 `transition.abort()` 可以无效化并取消此次切换。
### 预期返回值
- 可选择性返回 Promise :
- `resolve(true)` -> `transition.next()`
- `resolve(false)` -> `transition.abort()`
- `reject(reason)` -> `transition.abort(reason)`
- 可选择性返回 Boolean 值:
- `true` -> `transition.next()`
- `false` -> `transition.abort()`
### 详情
此钩子函数的调用顺序是从下至上。组件的 `canDeactivate` 钩子仅在子级组件的 `canDeactivate` 被断定( resolved )之后调用。
canActivate
最后更新于:2022-04-01 07:41:20
# `canActivate(transition) [-> Promise | Boolean]`
在验证阶段,当一个组件将要被切入的时候被调用。
### 参数
- [`transition {Transition}`](hooks.md#transition-object)
调用 `transition.next()` 可以断定( resolve )此钩子函数。调用 `transition.abort()` 可以无效化并取消此次切换。
### 预期返回值
- 可选择性返回 Promise :
- `resolve(true)` -> `transition.next()`
- `resolve(false)` -> `transition.abort()`
- `reject(reason)` -> `transition.abort(reason)`
- 可选择性返回 Boolean 值:
- `true` -> `transition.next()`
- `false` -> `transition.abort()`
### 详情
此钩子函数的调用顺序是从上之下。子级组件视图的 `canActivate` 钩子仅在父级组件的 `canActivate` 被断定( resolved )之后调用。
deactivate
最后更新于:2022-04-01 07:41:18
# `deactivate(transition) [-> Promise]`
在激活阶段,当一个组件将要被禁用和移除之时被调用。
### 参数
- [`transition {Transition}`](hooks.md#transition-object)
调用 `transition.next()` 可以断定( resolve )这个钩子函数。注意,这里调用 `transition.abort()` 并不会把应用回退到前一个路由状态因为此时切换已经被确认合法了。
### 预期返回值
- 可选择性返回 Promise
- `resolve` -> `transition.next()`
- `reject(reason)` -> `transition.abort(reason)`
### 详情
此钩子函数的调用顺序从下至上。父级组件的 `deactivate` 会在子级组件的 `deactivate` 被断定( resolved )之后被调用。
新组件的 `activate` 钩子函数会在所有组件的 `deactivate` 钩子函数被断定( resolved )之后被调用。