《vuejs快跑构建触手可及的高性能web应用》读书笔记

1.cdn:内容分发网络(CDN)是将资源托管到全世界各处的服务器上以实现快速分发。CDN版本对于开发和快速验证比较有用,但是将unpkg应用于生产环境前,需要检查它是否适合你。

 

2.假值包括false、undefined、null、‘’、NAN。

 

3.使用v-show两个场景:

  频繁切换某些内容;

  如果元素包含任何图片,那么仅使用css隐藏父节点可以使浏览器在图片显示之前就加载它,这意味着一旦v-show变成真值,图片就可以显示出来。如果是v-if指令,图片就直到要显示时才开始加载。

 

4.响应式如何实现:

  vue修改了每个添加到data上的对象,当该对象发生变化时vue会收到通知,从而实现响应式。对象的每个属性会被替换为getter和setter方法,因此可以像正常对象一样使用它,但当你修改这个属性时,vue会知道它发生了变化。

 

5.为对象添加新的属性。

  因为getter,settter方法是在vue实例初始化的时候添加的,只有已经存在的属性是响应式的,当为对象添加一个新的属性的时候,直接添加并不会使这个属性成为响应式的。

1 const vm = new Vue({
2   data: {
3     formData: { 
4       username: 'someuser'
5     }
6   }
7 });

  有几种方法解决这个问题:

  (1)最简单的办法是在初始化时对象上定义这个属性,并把它的值设置为undefined。上例中的formData对象会变成下面这样:

1 formData: {
2     username: 'someuser',
3     name: undefined   
4 }

  (2) 也可以使用Object.assign()来创建一个新的对象然后覆盖原来对象,当需要一次性更新多个属性时,这是最有效的方法:

1 vm.formData = Object.assign({}, vm.formData, {
2     name: 'Some User'
3 });

  (3)Vue还提供了Vue.set()方法,可以使用它将属性设置为响应式的:

1 Vue.set(vm.formData, 'name', 'Some User');

  在组件内部也可以使用this.$set来调用这个方法。

 

6.设置数组的元素

  不能直接使用索引来设置数组的元素。下面的做法是行不通的:

1 const vm = new Vue({
2     data: {
3         dogs: ['Rex', 'Rover', 'Henrietts', 'Alan']
4     }
5 });
6 vm.dogs[2] = 'Bob'

  有两种方法可以解决这一问题。一种是使用.splice( )方法移除旧元素并添加新元素:

vm.dogs.splice(2, 1, 'Bob');

  另一种是使用Vue.set( ):

Vue.set(vm.dogs, 2, 'Bob');

 

7.设置数组的长度

  在javascript中,可以设置一个数组的长度,自动让空元素填充数组至该长度或者截掉数组的尾部。不过这个方法不能用于处理data对象中的数组,因为Vue不能检测到该操作对数组的任何更改。

 

8.到目前为止已经了解如何将数据输出到模板,以及vue的响应式能力如何做到让模板随着数据的跟新而更新。但这只是单向数据绑定。试着运行下面的代码,你会发现inputText会保持不变。输入框下面的文本也会保持不变。

 1 <div id="app">
 2   <input type="text" :value="inputText">
 3   <p>inputText: {{inputText}}</p>
 4 </div>
 5 <script>
 6   new Vue({
 7     el: '#app',
 8     data: {
 9        inputText: 'initial value'
10     }
11   })
12 </script>

可以使用v-model指令,它作用于输入框元素,将输入框的值绑定到data对象的对应属性上,因此输入框不但会接收data上的初始值,而且当输入框内容更新时,data上的属性值会被更新。

 1   <div id="app">
 2      <input type="text" v-model="inputText">
 3      <p>inputText: {{inputText}}</p>
 4   </div>
 5   <script>
 6     new Vue({
 7        el: '#app',
 8        data: {
 9           inputText: 'initial value'
10        }
11     })
12  </script>

    

9.method妙用

(1)将代表状态的数字-转换为可读的、描述真实状态的字符串

 1 <div id="app">
 2     <p>当前状态: {{statusFromId(status)}}</p>
 3 </div>
 4  <script>
 5         new Vue({
 6         el: '#app',
 7         data: {
 8         status: 2
 9         },
10         methods: {
11         statusFromId(id) {
12            const status = ({
13                0: '睡觉',,
14             1: '吃饭',,
15             2: '学习vue'
16            })[id];
17            return status || '未知状态:' +id;
18             }
19         }
20     })
21  </script>

(2)过滤for循环中的数据,避免v-for和v-if混用

 1 <div id="app">
 2     <ul>
 3         <li v-for="number in filterPositive(numbers)">{{number}}</li>
 4     </ul>
 5 </div>
 6 <script>
 7     new Vue({
 8         el: '#app',
 9         data: {
10             numbers: [-5, 0, 2, -1, 1, 0.5]
11         },
12         methods: {
13             filterPositive(numbers) {
14                 return numbers.filter((number)=> number > 0);  // [2, 1, 0.5]
15             }
16         }
17     })
18 </script>

 

10. 在vue2.0中,mounted钩子触发时并不保证元素已经被添加到DOM上。如果想保证元素已经被添加,可以调用Vue,nextTick()方法,也可以通过this.$nextTick()调用,并传入一个回调函数,在回调函数中添加需要在元素被添加到DOM之后运行的代码。

 1 <div id="app">
 2     <p>Hello world</p>
 3 </div>
 4 <script>
 5     new Vue({
 6         el: '#app',
 7         mounted() {
 8             // 元素可能还没添加到DOM上
 9             this.$nextTick(()=>{
10                  // 确定元素已经被添加到DOM上了
11             })
12         }
13     })
14 </script>       

 

11. 使用自定义指令directive, 来实现一个闪烁效果:

 1 <body>
 2   <div id="app">
 3     <p v-blick>我会闪烁</p>
 4   </div>
 5 </body>
 6 <script>
 7   new Vue({
 8     el: '#app',
 9     data: {},
10     directives: {
11       'blick': {
12           bind(el) {
13               let isVisible = true;
14               setInterval(() => {
15                   isVisible = !isVisible;
16                   el.style.visibility = isVisible ? 'visible' : 'hidden';
17               }, 1000)
18           }
19       }
20     }
21   })
22 </script>

 

 12. prop使用和.sync修饰符

  如果prop的值不是字符串,那么就必须使用v-bind指令。

<display-number :number = "10"></display-number>

  数据通过prop从父级组件传递给子组件中,当父级组件中的数据更新时,传递给子组件的prop也会更新。但是你不可以在子组件中修改prop。这就是所谓的单向下行绑定,防止子组件在无意中改变父级组件的状态。

  然而,双向数据绑定在某种情况下可能很有用。如果想要使用双向绑定,可以使用一个修饰符来实现 : .sync修饰符。它只是一个语法糖:

<count-from-number :number.sync="numberToDisplay" />

 

13.自定义输入组件与v-model

与.sync修饰符相似,可以在组件上使用v-model指令来创建自定义输入组件。这里同样也是一个语法糖。请看示例:

<input-username  v-model="username" /> 

上面的代码等效于:

<input-username :value="username"  @input="value => username=value" />

 

14.响应路由变化

  当/user/1234 与/user/5678 相互切换时,其中相同的组件会被重用,于是第一章所涉及到的生命周期钩子,诸如mounted,都不会被调用。不过,你可以使用beforeRouteUpdate导航守卫在URL动态部分变化时运行一些代码。

 我们创建一个PageUser组件,它在挂载的时候会调用一次API,并且在路由变化时还会再调用一次:

<template>
    <div v-if="state === 'loading'">
        loading user...
    </div>
    <div>
       <h1>user: {{userInfo.name}}</h1>
    </div>
</template>

<script>
    export default {
        data: ()=> ({
             state: 'loading',
             userInfo: undefined
        }),
        mounted() {
             this.init();
        },
        beforeRouteUpdate(to, from, next) {
             this.state = 'loading';
             this.init();
             next();
        },
        method: {
            init() {
                 fetch(`/api/user/${this.$route.params.userId}`)
                 .then((res)=> res.json())
                 .then((data)=> {
                      this.userInfo = data;
                 });}
           }
       }
   }
</script>                                   

 

15.路由参数作为组件属性传入

除了在组件中使用this.$route.params,还可以让vue-router将params作为路由组件的props传入。以如下组件为例:

const PageUser = { 
    template: '<p>ID: {{ $route.params.userId }}</p>'
};
const router = new VueRouter({
    routes: [{
         path: '/user/:userId ',
         component: PageUser 
    }]
});

当导航至/user/1234的时候,‘ID:1234’就会被输出到页面上。

要想让vue-router改为将userId作为组件的一个属性传入,你可以在路由中指定props:true

const PageUser = {
     props: ['userId],
     template: '<p>user ID: {{ userId }}</p>'
};
const router = new VueRouter({
     routes: [
          path: '/user/:userId',
          component: PageUser,
          props: true
     ]
});

使用props代替$route.$params的好处是:组件与vue-router不再紧密耦合。设想一下,将来你想在一个页面上展示多个用户,使用第一个例子的代码就会很棘手,但使用第二个例子的代码就会变得很简单,因为只要在另一个页面调用该组件就好了,就像它是一个与路由无关的通用组件那样。

 

16.vue-router中的tag属性

<router-link to="/user/1234" tag="li">go to user 1234</router-link>

这会在页面上渲染出如下结果:<li> go to user 1234 </li>

由此,在它上面悬停也就不会给你带来任何关于这个链接的消息,也不能通过鼠标右键在新窗口打开这个链接;

为了解决这个问题,可以在<router-link>元素里面加上锚点标签:

<router-link to="/user/1234" tag="li"><a>go to user 1234</a></router-link>

现在,渲染出来的html就是下面这样:

<li><a href="/user/1234" >go to user 1234</a></li>

如果想给<router-link>添加一个事件处理器,可以使用.native修饰符来监听:

<router-link to="/blog" @click.native="handleClick">blog</router-link>

 

17.导航守卫

当你维护的是一个拥有大量路由的网站,于是会发现另一个很有用的特性,它就是路由元信息。你可以在路由上添加一个meta属性,并在守卫那里重新获取它。例如,在account路由上设置一个requiresAuth属性,然后在守卫中查看该属性:

const router = new VueRouter({ 
    routes: [{
         path: '/account',
         component: PageAccount,
         meta: {
             requiresAuth: true
        }
    }]
});

router.beforeEach((to, from, next)=> {
     if (to.meta.requiresAuth) {
          next('/login');
     } else {
          next();
     }
})

当使用嵌套路由时,to.meta指向的是子路由的元信息,而非其父路由。也就是说,如果你在/account上添加了meta对象,而用户访问的是/account/email,则所获得的meta对象是关于该子路由的,而非父路由。可以通过遍历to,matched的方式来曲线救国,

它同样也包含了父路由的元信息:

router.beforeEach((to, from, next) => {
  const requiresAuth = to.matched.some((record) => {
     return record.meta.requiresAuth;
  })
  if (to.meta.requiresAuth) {
     next('/login');
  } else {
     next();
  }
})

 

18.afterEach,可用于设置页面标题

const router = new VueRouter({
  routes: [{
     path: '/blog',
     components: PageBlog,
     meta: {
         title: 'welcome to my blog'
     }
  }]
});
router.afterEach((to) => {
   document.title = to.meta.title;
});

 

19.使用vuex和websocket,实现用户在页面上所拥有的的消息数量

组件代码:

const NotificationCount = {
  template: `<p>messages: {{messageCount}}</p>`,
  computed: {
     messageCount() {
       return this.$store.state.messages.length;
     }
  },
  mounted() {
    this.$store.dispatch('getMessages');
  }
};

然后下面使我们的vuex store(store/index.js)

let ws;
export  default  new Vuex.Store({
  state: {
     messages: []
  },
  mutations: {
     setMessages (state, messages) {
        state.messages = messages;
     }
  },
  actions: {
     getMessages ({ commit }) {
       if (ws) { return ; }
          ws = new WebSocket('/api/message');
          ws.addEventListener('message', (e)=> {
             const data = JSON.parse(e.data);
             commit('setMessages ', data.message);
          });
       }
    }
});             

 

阮一峰webSocket 教程: http://www.ruanyifeng.com/blog/2017/05/websocket.html?utm_source=tuicool&utm_medium=referral

实例对象的onmessage属性,用于指定收到服务器数据后的回调函数。

 

 

posted @ 2020-05-15 15:19  鼓舞飞扬  阅读(430)  评论(0编辑  收藏  举报