模板内能够放表达式,可是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板太重且难以维护。例如:html
<div id="example"> {{ message.split('').reverse().join('') }} </div>
因此,对于任何复杂逻辑,都应当使用计算属性。前端
<div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div>
computed: { // 计算属性的 getter reversedMessage: function () { // `this` 指向 vm 实例 return this.message.split('').reverse().join('') } }
computed计算属性实质上就是对模版语法的增强,可让咱们编写更为复杂的逻辑。
传入的静态属性会绑定在组件内最外层元素上vue
<blog-post title="My journey with Vue"></blog-post>
数字、字符串、对象、数组等node
<blog-post v-bind="post"></blog-post>
<a @select="selectItem"></a>
├── src │ ├── const │ │ ├── const.js │ │ │ └── main.js └── ...
在 const.js 文件下,设置常量react
// const.js export default { install(Vue,options){ Vue.prototype.global = { title:'全局', isBack: true, isAdd: false, }; } }
引入webpack
//引入全局常量 import constant from './const/const.js' Vue.use(constant);
而后咱们就能够在任何地方使用了web
//经过js方式使用: this.global.title //或在 html 结构中使用 {{global.title}}
一、计算属性必须返回值
二、计算属性是基于他的依赖来自动执行的,只有当依赖属性发生变化了,它才会从新计算
三、method能够不须要返回值,它依赖事件的调用,不会自动执行
四、当你在抉择的时候,你要注意你是否须要缓冲数据,若是须要那你就使用计算属性。面试
一般咱们自定义一些指令是知足咱们对DOM操做的需求Vue里面有许多内置的指令,好比v-if和v-show,这些丰富的指令能知足咱们的绝大部分业务需求,不过在须要一些特殊功能时,咱们仍然但愿对DOM进行底层的操做,这时就要用到自定义指令。vue-router
自定义指令的几个钩子函数:express
钩子函数的参数:
name:指令名,不包括 v- 前缀。
value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为2。
oldValue:指令绑定的前一个值,仅在update和 componentUpdated钩子中可用。不管值是否改变均可用。
expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
arg:传给指令的参数,可选。例如 v-my-directive:foo中,参数为 "foo"。
modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为{ foo: true, bar: true }。
vnode:Vue 编译生成的虚拟节点。
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', { bind: function (el, binding, vnode) { var s = JSON.stringify el.innerHTML = 'name: ' + s(binding.name) + '<br>' + 'value: ' + s(binding.value) + '<br>' + 'expression: ' + s(binding.expression) + '<br>' + 'argument: ' + s(binding.arg) + '<br>' + 'modifiers: ' + s(binding.modifiers) + '<br>' + 'vnode keys: ' + Object.keys(vnode).join(', ') } }) new Vue({ el: '#hook-arguments-example', data: { message: 'hello!' } })
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。
// router.js import Vue from "vue"; import Router from "vue-router"; // 【1】引入router import Home from "./views/Home.vue"; // 组件引入 Vue.use(Router); // 【2】使用 // 【3】new Router(param) // param 是一个路由配置对象 export default new Router({ routes: [ { path: "/", name: "home", component: Home }, { path: "/about", name: "about", // 懒加载 component: () => import(/* webpackChunkName: "about" */ "./views/About.vue") } ] });
引入路由配置
// main.js import Vue from "vue"; import App from "./App.vue"; import router from "./router"; // 【1】引入 new Vue({ router, // 【2】绑定路由 render: h => h(App) }).$mount("#app");
// app.vue <template> <div id="app"> <router-link to="/">首页</router-link> <router-link to="/about">Abour</router-link> <p> <router-view></router-view> </p> </div> </template> <script> export default { name: "APP", data () { return { } } }; </script>
这样就能够实现简单的路由切换。
经过Home组件来区分$route和$router的区别:
<template> <div class="home"> Home <button @click="goBack">返回</button> </div> </template> <script> export default { name: "home", mounted () { console.log(this.$route); }, methods: { goBack() { this.$router.go(-1); } } }; </script>
this.$router来访问路由器,进行一些路由跳转等操做。this.$route能够拿到当前路由信息。
好比: this.$router.go(-1);
来实现回退,console.log(this.$route);
来查看当前路由。
咱们能够在this.$route中拿到路由信息,好比一些参数和查询条件等。
vue-router提供了params、query、meta三种页面间传递参数的方式。
// 字符串,不带参数 /home this.$router.push('home') // 对象,不带参数 /home this.$router.push({ path: 'home' }) // params(推荐):命名的路由,params 必须和 name 搭配使用 /user/123 this.$router.push({ name:'user',params: { userId: 123 }}) // 这里的 params 不生效 this.$router.push({ path:'/user',params: { userId: 123 }}) // query:带查询参数,变成 /register?plan=private this.$router.push({ path: 'register', query: { plan: 'private' }}) //meta方式:路由元信息 export default new Router({ routes: [ { path: '/user', name: 'user', component: user, meta:{ title:'我的中心' } } ] })
//经过 $route 对象获取,注意是route,么有r this.$route.params this.$route.query this.$route.meta
咱们常常须要把某种模式匹配到的全部路由,全都映射到同个组件。例如,咱们有一个 User 组件,对于全部 ID 各不相同的用户,都要使用这个组件来渲染。这时候咱们须要设置动态路由参数来实现:
{ // // 动态路径参数 以冒号开头 path: '/user/:id', name: 'user', component: User }
一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,能够在每一个组件内使用。因而,咱们能够更新 User 的模板,输出当前用户的 ID:
const User = { template: '<div>User {{ $route.params.id }}</div>' }
你能够在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params 中。例如:
注意点
当使用路由参数时,例如从/user/foo
导航到/user/bar
,原来的组件实例会被复用。由于两个路由都渲染同个组件,比起销毁再建立,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
使用watch监听:
const User = { template: '...', watch: { '$route' (to, from) { // 对路由变化做出响应... } } }
<template> <div class="user"> <h1>This is an user page</h1> <p>{{$route.params.id}}</p> <router-link to="/user/22">去22</router-link> </div> </template> <script> export default { created() { console.log("created"); }, // 使用导航守卫 beforeRouteUpdate (to, from, next) { // react to route changes... // don't forget to call next() console.log(to, from , next); } } </script>
若是咱们想实现/user/12/more或者是user/userother这类的路由,并且要在user组件下去动态匹配内容的显示。这时候就可使用咱们的嵌套路由。
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // 当 /user/:id/profile 匹配成功, // UserProfile 会被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 当 /user/:id/posts 匹配成功 // UserPosts 会被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] } ] })
这时候对咱们的User组件也须要作必定的处理,添加一个<router-view></router-view>
const User = { template: ` <div class="user"> <h2>User {{ $route.params.id }}</h2> <router-view></router-view> </div> ` }
这时候咱们匹配/user/12/profile
这些都是能够的了~
触发跳转能够是:
<router-link :to="'/userprofile'+ $route.params.id +'/'"></router-link> // 或者是 <router-link :to="profile" append></router-link>
若是没匹配到,咱们想要让他显示一个提示性的页面的时候,在怎么作呢?
定义一个空白子路由,若是匹配不到路由会匹配该路由。
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ // 当 /user/:id 匹配成功, // UserHome 会被渲染在 User 的 <router-view> 中 { path: '', component: UserHome }, // ...其余子路由 ] } ] })
有时候咱们须要js去动态的跳转路由,编程式路由很合适。
在 Vue 实例内部,你能够经过 $router 访问路由实例。所以你能够调用 this.$router.push。这个方法会向 history 栈添加一个新的记录,因此,当用户点击浏览器后退按钮时,则回到以前的 URL。
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由,提供路由的名称 router.push({ name: 'user', params: { userId: 123 }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
注意点: 若是提供了 path,params 会被忽略,上述例子中的 query 并不属于这种状况。取而代之的是下面例子的作法,你须要提供路由的 name 或手写完整的带有参数的 path:
const userId = 123 router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 这里的 params 不生效,因此不要这么写 router.push({ path: '/user', params: { userId }}) // -> /user
router.replace(location, onComplete?, onAbort?)
跟 router.push 很像,惟一的不一样就是,它不会向 history 添加新记录,而是跟它的方法名同样 —— 替换掉当前的 history 记录。以后回退是不会回退回去的,由于history队列中已经没了
router.go(n)
这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,相似 window.history.go(n)。
// 在浏览器记录中前进一步,等同于 history.forward() router.go(1) // 后退一步记录,等同于 history.back() router.go(-1) // 前进 3 步记录 router.go(3) // 若是 history 记录不够用,那就默默地失败呗 router.go(-100) router.go(100)
vue-router路由提供了两种路由模式:hash模式和history模式。
hash模式
它是利用hash来模拟完整的Url,经过hashChange来监听hash变化,当页面变化的时候不会刷新页面。
history模式
若是不想要很丑的 hash,咱们能够用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须从新加载页面。
//设置mode属性,设置路由模式 const router = new VueRouter({ mode: 'history', routes: [...] })
不过这种模式要玩好,还须要后台配置支持。由于咱们的应用是个单页客户端应用,若是后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就很差看了。
vue-router提供了一些导航守卫来,控制咱们的路由跳转和守卫导航。有多种机会植入路由导航过程当中:全局的, 单个路由独享的, 或者组件级的。
全局守卫【全局前置守卫】
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })
导航守卫是异步的,所以导航在守卫完成以前都是等待状态,所以须要 咱们手动resolve.
next();必定要调用该方法来 resolve 这个钩子
next(false): 中断当前的导航。若是浏览器的 URL 改变了 (多是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
next('/') 或者 next({ path: '/' }): 跳转到一个不一样的地址。当前导航中断。
确保要调用 next 方法,不然钩子就不会被 resolved。
路由独享的守卫
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
参数同全局前置守卫。
组件内守卫
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 由于当守卫执行前,组件实例还没被建立 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,可是该组件被复用时调用 // 举例来讲,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 因为会渲染一样的 Foo 组件,所以组件实例会被复用。而这个钩子就会在这个状况下被调用。 // 能够访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 能够访问组件实例 `this` } }
使用场景:
beforeRouteEnter (to, from, next) { next(vm => { // 经过 `vm` 访问组件实例 }) }
// 路由发生变化的时候 beforeRouteUpdate (to, from, next) { // just use `this` this.name = to.params.name next() }
这个离开守卫一般用来禁止用户在还未保存修改前忽然离开。该导航能够经过 next(false) 来取消。
beforeRouteLeave (to, from , next) { const answer = window.confirm('Do you really want to leave? you have unsaved changes!') if (answer) { next() } else { next(false) } }
导航被触发。 在失活的组件里调用离开守卫。 调用全局的 beforeEach 守卫。 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。 在路由配置里调用 beforeEnter。 解析异步路由组件。 在被激活的组件里调用 beforeRouteEnter。 调用全局的 beforeResolve 守卫 (2.5+)。 导航被确认。 调用全局的 afterEach 钩子。 触发 DOM 更新。 用建立好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
好长呀,感受记不住:
咱们来简化如下,记住一些关键步骤。
本组件调用离开守卫 -- 全局的beforeEach -- 全局的before Resolve -- 导航确认,-- 调用全局的afterEach -- DOM更新 --