Induction to Vue.js

1 篇文章 0 订阅
var vm = new Vue({
	//the existed DOM element that this instance will mount
	el: "#app",
	//the template that will be rendered, if not existed, the outerHTML of mounted element will be regarded as template.
	template: '',
	//the attribute of this vue instance
	data: {
	...
	},
	//computed attribute
	computed: {
	},
	//the methods
	methods: {
	...
	},
	//the child components
	components: {
	...
	},
	//lifecycle hooks
	beforeCreate() {
	},
	...
	//the vue-router
	router,
	//the vuex, manage all status of whole application 
	store,
	//the render function
	render,
})

每一个 Vue.js 应用都是通过 Vue 构造函数创建一个根实例来启动的,它的构造函数接受

挂载元素 el:提供一个已经存在的 DOM 元素作为挂载目标,该元素所有内容将被 Vue 生成的DOM 替换,也就是 vm.$el(该属性将在 mounted 后生成,在 mounted 之前不可访问)。如果没有指定el, 则模板被渲染为文档之外的元素, 可以通过 vm.$mount方法 来显式指定挂载元素,也可以通过通过原生的 DOM API 来添加到指定元素。

1.  vm = new Vue({...}).$mount("#app")
2.  var vm = new Vue({...}).$mount();
	document.getElementById("app").appendChild(vm.$el);

数据 data:data 是一个对象,或者是一个返回对象的函数(在组件内,data 必须是一个函数)。data 内存放该组件所需的数据, 推荐只使用 (key, value) 形式。vm 实例代理了 data 所有属性,并为每个属性生成对应的 getter, setter(因此,属性的改动是响应式的,同时,通过方法在后期添加的属性不是响应的, 因为它没有对应的 getter, setter)。vm.$data.key 等价于 vm.key。

模板 template: 模板内的内容将会被 render 函数渲染,生成的元素将会替换挂载元素的内容。如果 Vue 实例里指定了 render 函数,则 template 选项将被忽略。

计算属性 computed:有时需要在模板内进行运算,如果逻辑较复杂,模板将不再简单清晰,这个时候就需要使用计算属性。计算属性将会自动识别它的依赖, 当它的依赖改变时,计算属性会自动更新,一般是同步操作。也就是说,计算属性的结果是会被缓存的,只有当依赖改变时,才会重新计算,每次调用都是直接返回缓存,这在进行大量计算,比如遍历很大的数组的操作时,是很有利的。这也是计算属性和方法的区别,方法每一次被调用,都会重新运行一次代码。而同样的,计算属性的功能也可以通过 watch 选项实现。

1. watch 
var vm = new Vue({
	data: {
		firstName: 'Foo',
		secondName: 'Bar',
		fullName: 'Foo Bar'
	},
	watch: {
		'firstName': function(newFirstName) {
			this.fullName = newFirstName + ' ' + this.secondName;
		},
		'secondtName': function(newSecondName) {
			this.fullName = this.firstName + ' ' + newSecondName;
		},	
	}
})
2. computed
var vm = new Vue({
	data: {
		firstName: 'Foo',
		secondName: 'Bar'
	},
	computed: {
		fullName: this.firstName + ' ' + this.secondName;
	}
})

watch 也能实现相同的功能,但是wacth的代码看起来更重复,而且 fullName的更新也是命令式的。

计算属性不仅有 getter,还可以有 setter。

var vm = new Vue({
	data: {
		firstName: 'Foo',
		secondName: 'Bar'
	},
	computed: {
		fullName: {
			get: function() {
				return 	fullName: this.firstName + ' ' + this.secondName;
			},
			set: function(val) {
				var names = val.split(' ');
				this.firstName = names[0];
				this.secondName = names[names.length - 1];
			}
		}
	}
})
vm.fullName // Foo Bar
vm.fullName = 'Jone Doe' //data: [firstName: Jone, secondName: Doe]
watch: 是一个对象, key 是需要 wacth 的表达式, value 是表达式值改变时的回调。watch 优点是可以执行异步操作。比如计算属性是基于 price 和 quantity的,当quantity改变时,还需要到数据库读取 price,这不适合同步操作,这时候就可以使用watch了。
 var vm = new Vue({
	data: {
		a: ''
	},
	watch: {
		'a': function(newValue, oldValue) {
		...
		}
	}
})

方法 methods: 常用于实现响应事件, 方法体内的 this 自动绑定为对应的 vm 实例。慎重使用箭头函数,因为箭头函数默认绑定父级上下文。

组件 components:存放子组件,该子组件只能在父作用域中使用。

生命周期钩子: Vue 实例从创建到销毁经历了许多步骤, vue 提供了一些 生命周期钩子, 使得用户有机会在各个步骤执行自定义的操作。生命周期图

路由 router: 实现路由转换

状态管理 vuex: 实现状态管理, 适用于应用状态较多且逻辑较为复杂的情况。

Vue Global API

1. var Compo = Vue.extends({
	template: "...",
    data() {return {...}}
   })
   new Compo().mount('#demo')
 
   create a subclass of base Vue constructor, the argument should be an object containing component options, and the data should be function
 
2. Vue.nextTick([callback: Function, context: Object])
   Defer the callback to be executed after the next DOM udpate cycle. Use it immediately after you've changed some data to wait for DOM update.
   eg.
   //modify data
   vm.msg = 'Hello'
   //DOM not update yet
   Vue.nextTick(function() {
   //DOM has updated here
   })
 
3. Vue.set(target:[Object, Array], key: [String, Number], value: any)
   Returns: the set value
   Set a property on an object. If the object | array is reactive, ensure the property is created as a reactive property and trigger view updates.
   Note that the object cannot be a Vue instance or the root data object of a Vue instance.
 
4. Vue.delete(target:[object, Array], key: [String, Number])
   Delete a property on an object.
   
5. Vue.filter(id: String, [definition: Function])
   Register or retrieve a filter
 
6. Vue.component(id:String, [definition: [Function, Object]])
   Register or retrieve a global component. Registration also automatically sets the components'name with the given id.
   a. Vue.component('my-component', Vue.extend({...}))
   b. Vue.component('my-component', {...})//call Vue.extend() automatically
   c. var MyComponent = Vue.component('my-component')
 
7. Vue.use(plugin: [Object, Function])
   Install a Vue.js plugin. If the plugin is an Object, it must expose an "install" method. If it is a function itself, it will be treated as the install method and the install method will be called with Vue as the argument. When this method is called on the same plugin multiple times, the plugin will be installed only once.
 
8. Vue.mixin(mixin: Object)
   Apply a mixin globally, which affects every Vue instance created afterwards. This can be used by plugin authors to inject custom behavior into components.
 
9. Vue.compile(template: String)
   compile a template string into a render function. Only available in the full build.
 
10. Vue.version
    Provide the installed version of Vue as a string

Vue 实例属性

1. vm.$data : Object
   the data object that Vue instance is observing, and Vue instance proxies access to the properties of its data object.
2. vm.$props : Object 
   the object representing the props current component has received, and Vue instance proxies access to the properties on its props object
3. vm.$el : HTMlElement
   the root DOM element that Vue instance is managing
4. vm.$options : Object
   used for custom properties
5. vm.$parent : Vue instance
   the parent Vue instance, if current instance has one
6. vm.$root : Vue instance
   the root Vue instance of current component tree. if the current instance has no parents, this value will be itself.
7. vm.$children : Array<Vue instance>
   the direct children components of current component. Note that there is no order guarantee for $children, and its not reavtive
8. vm.$slots : {[name: String]: ?Array<VNode>}
   used to programmatically access content distributed by slots. Each named slot has its own corresponding property(eg. the contents of slot="foo" will be found at vm.$slots.foo). The default property contains any nodes not includes in a named slot.
9. vm.$refs : Object
   an object that holds child components that have ref registered.
10. vm.$isServer : boolean
   Whether the current Vue instance is running on the server
11. vm.$attrs : {[key: String]: String}
   contains parent-scope attribute binding(except for class and style) that are not recognized as props.
12. vm.$listeners : {[key: String]: Function | Array<Function>}
   contains parent-scope v-on event listeners(without .native modifiers)

Vue 实例方法

1. vm.$watch
var unwatch = vm.$watch(expOrFunc, callback, [options]);
eg.
	vm.$watch('a', function(newValue, oldValue) {...},
		{
			deep: true,//watch the internal attribute change of 'a'
			immediate: true//trigger callback immediately with current value of 'a'
		}
	)
 
2. vm.$set(object, key, value) //the alias of Vue.set
 
3. vm.$delete(object, key)  //alias of Vue.delete
 
4. vm.$on(event, callback)  //listen custom define event of current vue instance, the event is emitted by child component
 
5. vm.$emit(event, parameter...)  //emit event, and pass parameter
 
6. vm.$once(event, parameter...)  //just trigger once, if triggered, delete the listener
 
7. vm.$off([event, callback]) //delete the listener of event
   case1: without argument. delete all listener of all event
   case2: only event. delete all listener of specified event
   case3: event and callback. delete the listener of this callback
 
8. vm.$mount(element: string) //mount vm.$el to specified DOM element
 
9. vm.$nextTick([callback])  //execute the callback when DOM udpate itself next time
   <div>{{msg}}</div>
	
   var vm = new Vue({
       data: {
	       msg: 'hello'
       },
       methods: {
           change() {
                this.message = 'world';
                vm.$el.textContent === 'world' // false
			    this.$nextTick(function() {
                	vm.$el.textContent === 'world' //true
                })
           }
       }
   })

Vue 指令

v-model: 使用 v-model 在表单控件上创建双向数据绑定,它能根据控件类型自动选取正确的方法来更新数据,比如 text, checkbox, radio 等。但实际上,v-model 只是vue 提供的语法糖,它实际上也只是监听用户输入,然后更新数据。需要注意的是,使用 v-model 后,它会忽略表单元素的 value, selected, checked 等特性的初始值,因为它使用 Vue 实例的初始值。V-model demo

v-if,v-else-if,v-else:v-if 用来判断是否需要渲染指定元素,其后可以跟 v-else-if 和 v-else,但必须紧随 v-if 元素块之后,否则将被认为无效内容。当想把 v-if 用在多个元素上时,可以使用包装元素 template。但需要注意,vue 总是会默认的尽最大可能的复用元素,比如v-if 和 v-else 中都使用了 text, 当条件变换时,vue会尝试复用这个 text,而不是销毁重建。如果想阻止这种行为,可以给每一个控件指定唯一的 key,这样 vue 就不会再复用该控件。V-if demo

v-show: v-show 和 v-if 类似,都是隐藏或者显示组件,区别在于 v-show 是简单改变 style display 为 none,而 v-if 是销毁组件然后重建。另外 v-show 不支持 template 语法。v-show demo

v-for:v-for 一般用来遍历数组或对象,用法如下。

  • 遍历数组:v-for = "item in items", v-for = "(item, index) in items"。其中,items是数组名,item 是每一项元素的别名, index 是每一项的索引。
  • 遍历对象: v-for = "value in object", v-for = "(value, key) in object",  v-for = "(value, key, index) in object"。 
  • 遍历整数: v-for = "n in 10" --> 会从1遍历到10.

v-for 还可以和 template 一起使用,也可以和自定义组件一起使用。v-for demo

v-bind: v-bind 被用来响应的更新 html 属性,形式为 v-bind:property="variable", eg. <a v-bind:href="url">. 这里,href 就和 vue 实例的 url 绑定起来, 当修改 url 时,href 也会动态更新。v-bind 可以简写为冒号,eg. <a  :href="url">. 并且,数据绑定经常用于操作元素的 class 列表和内联样式,Vue 特意增强了 v-bind 对 class 和 style的处理。表达式的结果除了是字符串以外,还可以是对象和数组。另外, v-bind 也可以用于自定义组件。

v-on: v-on 用来监听 DOM 事件并触发一些 JS 代码,可以简写为@符号,其形式一般为 v-on:event.modifier="FunctionName"。其中, event 是事件名,modifier 是事件修饰符,提供特殊功能,FunctionName是函数名。v-on 用在普通元素时,只能监听原生 DOM 事件,当用在自定义组件时,可以监听子组件触发的自定义事件。modifier 可以是 stop(阻止事件冒泡), prevent(阻止原生事件默认操作), self(只有当事件在该元素本身而不是子元素触发时,调用回调), once(回调只调用一次)

v-text:v-text 用法很简单,就是绑定元素的文本内容。<div v-text="msg"></div> 等价于 <div>{{msg}}</div>

v-once: v-once 表示只渲染该元素一次,之后的渲染和更新将把该元素及其子节点视为静态内容并跳过。

Vue 特殊属性

key:有相同父元素的系列子元素必须有独特的key,否则渲染可能会出错,常和 v-for 配合使用。

ref:被用来给元素或子组件注册引用信息(ref 指向它修饰的元素或组件),引用信息将会注册到父组件的ref 对象上。

slot:为了让组件可以组合,需要有一种方式混合父组件的内容和子组件自己的模板,这个过程称为 transclusion(内容分发),Vue 使用一个特殊元素 <slot>作为内容插槽。只有当子组件模板包含至少一个slot时,父组件的内容才可以被插入子组件模板内,否则将被丢弃。且在插入时,将替换整个slot的内容。而 slot 中的原始内容被称作备用内容,只有当父组件没有分发数据下来时,才会渲染备用内容。slot 也可以设置名字,没有名字的 slot 称为 default slot,在父组件中没有指定 slot 的分发内容都会到 default slot 中,有名字的slot 称为具名slot,父组件的分发内容可以指定slot。Slot_demo

is: is 属性常用在动态组件中。eg. <component :is="currentView"></component>. 通过改变 currentView, 动态的转换控件内容。

过滤器

过滤器的作用在于文本转换,只可作用于两个地方: {{mustache 插值}} 和 v-bind 表达式。过滤器的形式是:Vue.filter(id:String, [definition]:function),这会注册一个全局过滤器,可以通过 var filter = Vue.filter(id) 来获取已经注册过的过滤器。过滤器接受表达式的值作为过滤函数的第一个参数,并且,过滤器可以串联。

Vue.filter('capitalise', function(value) {
	...
})
var capitalise = Vue.filter('capitalise')
 
<div v-bind:id="rawId | capitalise"> {{msg | capitalise}}</div>

Style 与 Class 绑定

Vue 强化了 v-bind 和 style 与 class 的作用。

1. bind to object
case1:
   <div :class = "{active: isActive}"></div> //this means when isActive == true, <div> will have class: active
case2:  
   <div :class = "classObject"></div>
   data: {
     classObject: {
       active: true, //class name could be 'camelCase'
       'text-danger': false//class name should be put in parentheses when use 'kebab-case'
     }
   }
Tip: the class of v-bind could coexist with normal class. For example: <div class="static" :class="active: isActive"></div>, the class of <div> will be "static active" when isActive == true
2. bind to computed attribute
this mode is powerful and be used commonly.
<div v-bind:class="classObject"></div>
data: {
isActive: true,
error: null
},
computed: {
classObject() {
  return {
  active: this.isActive && !this.error,
  'text-danger': this.error && this.error.type === 'fatal'
  }
}
}
3. bind to array
<div :class="[activeClass, errorClass]">
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}
==> <div class="active text-danger"></div>
Tip: we can still use <div :class="[isActive? activeClass : '', errorClass]"></div> or <div :class="[{active: isActive}, errorClass]">
当在自定义组件上绑定 class 时,这些 class 将被添加到自定义组件模板的根元素上,并且这个根元素上已有的 class 不会被覆盖。

组件

组件是 Vue 最强大的功能之一。组件可以扩展 HTML 元素, 封装可重用的代码。在较高层面上,组件是自定义元素,拥有某种特殊功能。在某些情况下,组件也可以是原生 HTML 元素的形式,以 is 属性扩展。可以通过Vue.component(id:string, [definition]) 注册全局组件,也可以在 Vue 实例里创建局部组件(使用 component 选项),且局部组件只能使用于该Vue实例作用域。

//global Vue component
Vue.component('my-component', {
template: '...',//could only have one root element
data: function() {//must be function,otherwise the compiler will print error
return {...}
},
props:['msg', 'itemlist']//the interface connect parent component and child component. parent component pass parameter to child component's props
})
 
//local Vue component
new Vue({
el: '',
data: {},
...
components: {
'my-component-A' : {...},
'my-component-B' : {...}
}
})

组件意味着协同合作,通常的场景是父组件在它的模板里使用了子组件,它们之间必然需要通信:父组件需要传递数据给子组件,子组件要向父组件报告在它内部发生的事件。Vue 中,父组件向子组件传递数据通过 props 属性完成,子组件向父组件报告事件通过 emit 事件完成。如下图所示。

props down, events up

Vue 中, 组件的作用域是独立的,不应该也不能让子组件直接访问父组件的数据。为了让子组件能够使用父组件的数据,需要显示声明 props. 声明的 props 可以和 data 属性一样的使用。需注意的是, props是单向传递的,这意味着子组件不能擅自修改父组件的数据(JS 中数组和对象都是引用类型,在子组件中修改会影响父组件),如果这么做了, 会导致应用的数据流难以理解,也难以调试,因此Vue 会在控制台给出 warning。如果真的需要改变,可以使用以下方法。

1.define a local variable, and initialize it with props
props: ['counter'],
data: function() {
return {counter: this.counter}
}
 
2. define a computed attribute to process props
props: ['str'],
computed: {
trimedString() {
return this.str.trim();
}
}
组件的 props 还可以进行验证,如果传入的参数不符合条件, Vue 会发出 warning。
1. string array format
props = ['param1', 'param2']//with this format, there is no constraint
 
2. object format
props: {
propA: Number,//just specify type
propB: [String, Number],//could be string or number
propC: {type: String, required: true},//specify type, and the prop is required
propD: {type: Number, default: 100}, //specify type, and the default value
propE: {type: Object, default: function() {return {msg: 'hello'}}},//the default value of Object| Array should be returned by factory method
propE: {validator: function(value){return value > 10}}//could custom define validator
}
Tip: type could be String|Number|Boolean|Function|Object|Array, or custom defined constructor and use instanceof to check
Tip: Vue will do validate before initializing component, so in default or validator method, could not use data,computed attribute or methods.  

同样的,还可以给组件添加非 prop 属性,组件可以接收任意传入的属性,这些属性都会被添加到组件的根元素上。

在父子组件中,父组件通过 props 传递数据给子组件,同时,子组件通过自定义事件系统和父组件进行通信。

Every instance of Vue implement events interface
1. use $on(eventName) to listen on event
2. use $emit(eventName) to trigger event
Tip: Do not use $on to listen on the event that child component emit, should use v-on in template instead.
Tip: To listen on native event of root element of component, could use .native modifier, eg. v-on:click.native="doSomething"

在一些情况下,需要对一个prop进行双向绑定,即在子组件中修改一个prop的值时,也会影响父组件。这个特性很方便,但也破坏了单向数据流。并且在子组件中改变prop的代码和普通代码并没有区别,这给debug带来了很大的困难。因此 Vue 针对这种情况,提供了 .sync 修饰符,用以双向绑定,用法是 v-bind:foo.sync="bar"。这在子组件改变foo时,父组件 bar 也随之更新。但实际上,.sync 只是语法糖,Vue 会把 v-bind:foo.sync="bar" 扩展为 v-bind:foo = "bar" v-on:udpate:foo="var => bar = val". 这样,当子组件需要改变 foo的值时,需要显示触发 update:foo 事件,即 this.$emit('update:foo', newValue). 这和 v-model 也是类似的,<input v-model="foo"> 也就等价于 <input v-bind:value="foo" @input=“foo = $event.target.value”>. 

当然,有时候两个非父子关系的组件也需要通信。在简单场景下,可以使用一个Vue 实例来作为中央事件总线,在复杂场景下,应使用专门的状态管理模式 Vuex。

Conclusion: Communication between components.
 
1. Parent component to direct child component
   => props
2. Child component to direct parent component
   => custom defined event and this.$emit(eventName, arguments)
3. Parent component to non-direct child component || child component to non-direct parent component || between sibling components
 
   In Vue 1.0, we use $broadcast(to broadcast an event that propagates downward to all descendants (all children)) and $dispatch(to fire an event that propagates upward along the parent chain) to handle those kinds of event. Now in Vue 2.0, they are deprecated because:
   a. As the component’s tree structure gets larger, it becomes very hard to maintain and reason about. For each modification you do, you have to check if those events are still
      passed to their handlers correctly — which sometimes requires some workarounds until everything is back to normal. This means, in other words, events are tightly coupled with
      the component’s tree, which is always bad!
   b. Attaching multiple listeners isn’t that intuitive, because the normal behavior is to stop propagation on the first handler, unless you return true from it.
   c. There’s no explicit way to pass events to sibling components — a workaround we were using is this: this.$root.broadcast('event-name'), which doesn’t feel good, does it?
 
   The simplest solution is get rid of those methods altogether, and handle all the communications through event hub (or some call it event bus). In its simplest definition, it’s an empty Vue instance that you use globally to fire and listen for events anywhere you want in the component’s tree.
   So, obviously, like any other vue instance, we have these methods available for that:
   eventHub.$emit(eventName)// to emit an event.
   eventHub.$on(eventName)// to listen for an event.
   eventHub.$off(eventName)// to remove event listeners.
   You can emit event in any component and handle it in any other component without considering their relationship. But the disadvantage is that you can not tell which component is
triggering an event to which component.
 
   But the method is not ultimate, you can image how unmaintainable this can become as your app grows more in complexity. To handle this situation, you can use Vuex instead which is designed to resolve this kind of problem.
有的时候,需要在同一个挂载点切换不同的component, 这个时候,可以使用保留的 <component> 元素,动态的绑定到它的 is 属性,这样,就可以通过切换属性值来切换组件了。
<component :is="currentView"></component>
 
var vm = new Vue({
el : "#demo",
data: {
currentView: 'home'
},
components: {
home: {...},
about: {...},
help: {...}
}
})
 
or
 
import compA from 'src/components/A.vue'
import compB from 'src/components/B.vue'
 
var vm = new Vue({
el: '#demo',
data: {
currentView: 'compA'
},
components: {
compA : compA,
compB : compB
}
})

在进行组件切换时,可以选择保存当前组件的状态,避免重新渲染,这在购物车类型的组件是十分适用的。Vue 中,可以通过添加 <keep-alive>元素来包裹组件元素实现。

Tip: 在 Vue 中声明的 camelCase 的变量在 HTML 中需要转换为 kebab-case,因为HTML 是不区分大小写的。

Tip:在给属性赋值时,要注意区分字面量语法和动态语法。eg. <div id="dynamicId"></div>,这里, dynamicId是被当作字面量处理的,所以id就会是“dynamicId”,而对于 <div :id="dynamicId"></div>,这儿的dynamic就会被当作变量处理,当该变量值改变时,div的id属性就会改变。因此,当使用 v-bind 时,它后面的表达式会被当作 JS 表达式来处理。
Vue_component_share_data_demo
Vue_component_occupy_data_demo,Vue_component_props_demoVue_component_name_convention_demoVue_component_dynamic_props_demo

Vue_component_v-on_demo,Vue_component_event_bus_demoVue_dynamic_component_demoVue_dynamic_component_demo2Vue_component_keep_alive_demo

单文件组件 .vue文件

在现代UI开发中,相比于把代码库分离成三个大的层次(JS, HTML, CSS)并将其相互交织起来,把它们划分为松散耦合的组件再将其组合起来更合理一些。在一个组件里,其模板,逻辑,样式是内部耦合的,把它们搭配在一起实际上使得组件更加内聚和更容易维护。在webpack 构建中,因为.vue文件是自定义文件,浏览器不识别,因此通过 vue-loader对 .vue文件进行解析。

<template><!-- write template in html format instead of template string, its more readable and convinient-->
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script><!-- define the data and its operation-->
import componentA from './A.vue' //each .vue is a instance of Vue indeed, here, componentA is child component of current component

export default {//the object here is equal to the object of Vue constructor, new Vue({...})
  name: 'hello',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  components: {
  componentA
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

2.Advanced Vue

vue-router

路由中有三个基本的概念:route, routes, router.

  1. route 是一条路由,表示一个组件路径
  2. routes 是一组路由
  3. router 是一个机制,相当于一个管理者,用它管理路由

在 vue 中实现路由还是相对简单的,因为页面中所有内容都是组件化的,我们只需要把路径和组件对应起来,然后在页面中把组件渲染出来, vue 通过 vue-router 实现路由。路由对象会被注入每个组件中,赋值为 this.$route, 并且当路由切换时,路由对象会被更新。这意味着,在组件内部使用的 this.$route 总是指向该组件对应的路由。

在 vue-router中,它定义了两个标签 <router-link>, <router-view> 来对应点击和显示部分,点击某个部分,对应的组件就被渲染出来,所以 <router-link> 有一个非常重要的属性 to,定义了点击之后,路由要转换到哪儿去,如 <router-link to="/home">Home</router-link>. 一般,我们在 JS 文件中配置路由信息。<router-view> 相当于一个占位符,组件将被渲染到 <router-view>标签所在的地方。vue-router_simple_demo

//routes.js
import Home from "./components/Home.vue"
import About from './components/About.vue'
 
const routes = [
	{
	   path : "/home",
       component : Home
    },
    {
	   path : "/about",
       component : About
    },
    {
	   path : "/",//when enter page first time,there is nothing in page, because its path is '/', we do not config its component, now, we use redirect to map '/' to '/home'
       redirect : '/home'
    }
]
export default routes
 
//main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes.js'
 
Vue.use(VueRouter)
 
const router = new VueRouter({
	mode: history,//could be hash(by default, use URL hash value as route), history(based on HTML5 History API), abstract(support all JavaScript run-time enviroment)
    routes
})
 
const app = new Vue({
	router
}).$mount('#app')

动态路由

上面定义的路由都是严格匹配的,只有router-link 中的 to 属性和 JS 中一条路由中 path 一模一样,才能显示对应的组件 component。但有时现实却不是这样的,比如常见的用户登录界面/user/id,不同id的用户其实使用的是相同的组件,这样在写路由的时候,就不能把路由中的path 属性写成固定的字符串,需要给路径一个动态部分来匹配不同的用户 id. 在vue-router之中,动态部分以 : 开头,那么路径就变成了 /user/:id.  当整个router 注入到 Vue 根实例后,在组件内,就可以通过 this.$route 来获取到router实例,它有一个params 属性,就是用来存储动态参数的。params是一个对象,key就是route中定义的动态部分,比如 /user/:id就是 id, 属性值就是<router-link>中 to 属性中的动态部分,比如 to=“/user/123”,则this.$route.params.id => 123. 并且动态路由在来回切换时,由于是之下同一组件,vue 不会销毁再创建这个组件,而是复用这个组件,如果想要在组件来回切换的时候根据动态部分做点事情,一个方法是使用计算属性监听 this.$route的变化(每次进入该组件时,取得该组件对应的route),还有一种方法是在组件内使用 watch 来监听 $route的变化(只能监听在组件内切换的时候route的变化,当从其它组件切换到该组件,或从该组件切换到其它组件,该回调都不会被触发,因为组件会被destory掉)。 vue-router_dynamic_path_demo,vue-router_dynamic_path_demo2

嵌套路由

嵌套路由是针对于页面结构而使用的,比如/home页面下面还有分类,比如 home 是一个水果系统,它下面有apple,orange, pear等分类,我们只能在进入 home 页面后,才能进入它的分类页面,也就是它的子页面。vue-router针对这种情况,在配置 route时,可以通过 children 选项设置它的子页面。然后在 home component 中,需要添加它的子页面对应的 <router-link>,它的to 属性需要是 to=“/home/apple”.vue-router_nest_route_demo

命名路由

顾名思义,命名路由就是给路由命名,这样,在写 <router-link>的to 属性时,就可以给 to属性绑定一个对象,而不再只是一个字符串。

命名视图

一个 <router-view>就是一个视图,一个页面可以有多个视图,一个视图对应一个组件。vue-router_named_view_demo

编程式导航

编程式导航,也就意味着可以在代码中控制路由,包含以下几个跳转方法。

  • router.push(location)//history 中会有记录
  • router.replace(location)//history 不会有记录
  • router.go(n)//在history中前进或者后退n步

location的类型有下面几种

  • ‘home’
  • {path: 'home'}
  • {name: 'user', params: {userId: 123}}//named route, equal to '/user/123'
  • {path: 'register', query: {plan: 'private'}}//contain query parameter, equal to '/register?plan=private'

路由构造配置

declare type RouteConfig = {
	path: String,//could be '/', '/user/:id', '/user/:id?'(param can be optional), '/user/:id(\\d+)'(will be only matched when id is all number), '/user/*', '/user/(foo/)?bar'(make part of path optional by warpping with parens and add "?")
	component?: Component,
	name?: String,//for named route
	components?: {[name: String]: Component},//for named view
	redirect?: String | Location | Function,
	alias?: String | Array<String>,
	children?: Array<RouteConfig>,//for nested routes
	beforeEntry?: (to:Route, from:Route, next: Function) => void;
	meta?: any
}

钩子函数

全局钩子函数

全局的钩子函数定义在全局的路由对象中,有两个钩子函数

beforeEach: called before switch route

afterEach: called after switch route

组件的钩子函数

vue-cli, vue-router, vuex, iview, iview-cli, vue-resource, .vue, transition, keep-alive

3. Library

4. Comparisom with other frameworks














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用归纳法可以证明f(x)=O(2x):基础情况:f(0) = 1, f(1) = 3,都是O(2x)。归纳情况:假设f(k) = O(2k),则有f(k + 1) = f(k)·f(k−1) = O(2k·2k−1),由此可知f(k+1) = O(2k+1),证毕。 ### 回答2: 首先,通过计算我们可以发现f(x)的前几项为1、3、2、6、12、24、...,可以猜测f(x) = 2^x - 1。 然后我们使用归纳法来证明f(x) = O(2^x)。 基础步骤:当x = 0时,f(0) = 1,而2^0 = 1。所以基础步骤成立。 归纳假设:假设对于某个自然数k,f(k) = O(2^k) 成立。 归纳步骤:我们需要证明当x = k + 1时,f(k + 1) = O(2^(k + 1))。 根据题目给出的等式 f(x) = f(x − 1) * f(x − 2),我们可以得到: f(k + 1) = f(k) * f(k - 1)。 根据归纳假设,我们有 f(k) = O(2^k),并且 f(k - 1) = O(2^(k - 1))。 根据大O符号的性质,我们知道 O(a) * O(b) = O(a * b),所以有: f(k) * f(k - 1) = O(2^k) * O(2^(k - 1)) = O(2^k * 2^(k - 1)) = O(2^(2k - 1))。 我们可以进一步将 O(2^(2k - 1)) 写成 O(2^(k + 1)),因为 2^(2k - 1) = (2^k)^2 / 2 = 2^(k + 1)。 所以,根据归纳法,我们可以得出结论:对于所有自然数x,f(x) = O(2^x) 成立。 ### 回答3: 首先,令n为自然数,我们要证明f(x) = O(2^x)。 首先,我们来验证基本情况。当n = 0时,f(0) = 1,而2^0 = 1,因此基本情况成立。 然后我们假设对于所有k ≤ n的自然数,f(k) = O(2^k)成立,即假设f(k) ≤ C * 2^k,其中C为一个常数。 接下来,我们要证明对于n+1也成立。根据题目给出的条件:f(x) = f(x - 1) * f(x - 2),我们可以推导出 f(n+1) = f(n) * f(n-1)。 根据我们的假设f(n) ≤ C * 2^n和f(n-1) ≤ C * 2^(n-1),我们可以得出: f(n+1) = f(n) * f(n-1) ≤ (C * 2^n) * (C * 2^(n-1)) 进一步简化可以得到: f(n+1) ≤ C^2 * 2^n * 2^(n-1) = C^2 * 2^(2n-1) 因此,我们可以得到f(n+1) ≤ C^2 * 2^(2n-1),即f(n+1) = O(2^(2n-1))。 根据基本情况和归纳假设,我们可以得出对于所有自然数n,f(n) = O(2^n)成立。 因此,根据数学归纳法,我们可以证明f(x) = O(2^x)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值