Vue简单见解

钩子函数在beforeCreate之前,主要是初始化一些vm的属性,initState主要为定义的data属性进行obsever以及处理一些props、watch和computed

Vue官网中的约束源码解释 -- 生命周期 · Issue #12 · muwoo/blogsgithub.com/muwoo/blogs/issues/12

Vue官网中的约束源码解释 -- 生命周期 · Issue #12 · muwoo/blogs

initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, beforeCreate) initInjections(vm) // resolve injections before data/props initState(vm) nitProvide(vm) // resolve provide after data/props callHook(vm, created)
在beforeCreate和created之间,进行数据观测(data observer) ,也就是在这个时候开始监控data中的数据变化,同时初始化event/watcher 事件配置在created 和 beforeMount之间el选项的有无对生命周期过程的影响。首先系统会判断对象中有没有el选项,有el选项,则继续编译过程,没有el选项,则停止编译,也意味着暂时停止了生命周期,直到vm.$mount(el)template参数选项的有无对生命周期的影响。1.如果Vue实例对象中有template参数选项,则将其作为模板编译成render函数,2.如果没有template参数选项,则将外部的HTML作为模板编译(template),也就是说,template参数选项的优先级要比外部的HTML高,3.如果1,2条件都不具备,则报错为什么判断el要发生在判断template前面呢,Vue需要通过el的“选择器”找到对应的template在Vue中,有render函数这个选项,它以createElement作为参数,做渲染操作。当然你也可以不调用createElement,而直接嵌入JSX render选项参数比template更接近Vue解析器!所以综合排列如下:render函数选项 > template参数 > 外部HTML
new Vue({ el: #demo, render (createElement) { return (....) } })
Vue的编译过程——把模板编译成 render 函数,beforeMount和mounted钩子函数间的生命周期,el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用mounted钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。beforeMount 时 vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,数据值还未替换,mounted 时 会被替换为正确值beforeUpdate钩子函数和updated钩子函数间的生命周期,适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。重渲染(调用这两个钩子函数)的前提是被更改的数据已经被写入模板中beforeDestroy和destroyed钩子函数间的生命周期,beforeDestroy钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。destroyed钩子函数在Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

模板写在template参数选项

new Vue({ el: #app, template: <div id="app"><p>模板在templated参数中找到了哟~</p></div> })

外部HTML

<div id="app"><p>模板是在外部HTML中找到的~</p></div> new Vue({ el: #app })

Vue前端开发规范

组件名为多个单词

组件名应该始终是多个单词的,根组件 App 除外。

name 最好必须填写
export default { // 正例 name: TodoItem, // 反例 name: Todo, }

组件数据

组件的定义只接受function

必须是返回一个对象的函数,对象必须是纯粹的对象 (含有零个或多个的 key/value 对)
// 正例 export default { data () { return { foo: bar } } } // 在一个 Vue 的根实例上直接使用对象是可以的, // 因为只存在一个这样的实例。 new Vue({ data: { foo: bar } }) // 反例 export default { data: { foo: bar } }

Prop定义

一般只获取使用,不要对其重新赋值
props: { status: String } // 更好的做法! props: { status: { type: String, required: true, validator: function (value) { return [ syncing, synced, version-conflict, error ].indexOf(value) !== -1 } } } // 反例 props: [status]

为v-for设置键值

建议尽可能在使用v-for时提供key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
<ul> <li v-for="todo in todos" :key="todo.id" > {{ todo.text }} </li> </ul>

watch定义

当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的
watch:{ // 可用字符串 监听对象属性 a: { handle(val) {}, // 深度监听 deep: true, // 立即执行 immediately: true } }

避免 v-if 和 v-for 用在一起

当v-if与v-for一起使用时,v-for具有比v-if更高的优先级。
// 正例 <ul v-if="shouldShowUsers"> <li v-for="user in users" :key="user.id" > {{ user.name }} </li> </ul>

为组件样式设置作用域

class 类名(使用 BEM 约定) 使用创建 独立作用域, 或者用scoped 创建
<template> <button class="c-Button c-Button--close">X</button> </template> <!-- 使用 BEM 约定 --> <style> .c-Button { border: none; border-radius: 2px; } .c-Button--close { background-color: red; } </style> <style scoped> .button { border: none; border-radius: 2px; }

组件文件

只要有能够拼接文件的构建系统,就把每个组件单独分成文件,当你需要编辑一个组件或查阅一个组件的用法时,可以更快速的找到它。
components/ |- TodoList.vue |- TodoItem.vue

紧密耦合的组件名

和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
components/ |- TodoList.vue |- TodoListItem.vue |- TodoListItemButton.vue components/ |- SearchSidebar.vue |- SearchSidebarNavigation.vue

多个特性的元素

多个特性的元素应该分多行撰写,每个特性一行。
<img src="https://vuejs.org/images/logo.png" alt="Vue Logo" >

: key 属性的使用

keep-alive主要是为了缓存

当创建和编辑的页面使用的是同一个component,默认情况下当这两个页面切换时并不会触发vue的created或者mounted钩子,官方说你可以通过watch $route的变化来做处理,但其实说真的还是蛮麻烦的。后来发现其实可以简单的在 router-view上加上一个唯一的key,来保证路由切换时都会重新渲染触发钩子了。这样简单的多了
<keep-alive> <router-view :key="key"></router-view> </keep-alive> computed: { key() { // 或者 :key="$route.path" 只要保证key唯一就可以了 return this.$route.name !== undefined? this.$route.name + +new Date(): this.$route + +new Date() } }

简单的计算属性

简单的属性计算,

计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :

计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值
computed: { basePrice: function () { return this.manufactureCost / (1 - this.profitMargin) }, discount: function () { return this.basePrice * (this.discountPercent || 0) }, finalPrice: function () { return this.basePrice - this.discount } } // computed: { price: function () { var basePrice = this.manufactureCost / (1 - this.profitMargin) return ( basePrice - basePrice * (this.discountPercent || 0) ) } }

vs methods 每当触发重新渲染时,调用方法将总会再次执行函数

vs watch 命令式且重复的

<div id="demo">{{ fullName }}</div> // watch var vm = new Vue({ el: #demo, data: { firstName: Foo, lastName: Bar, fullName: Foo Bar }, watch: { firstName: function (val) { this.fullName = val + + this.lastName }, lastName: function (val) { this.fullName = this.firstName + + val } } }) // computed var vm = new Vue({ el: #demo, data: { firstName: Foo, lastName: Bar }, computed: { fullName: function () { return this.firstName + + this.lastName } } })
带引号的特性值
<app-sidebar :style="{ width: sidebarWidth + px }"></app-sidebar> // <app-sidebar :style={width:sidebarWidth+px}></app-sidebar>

单文件组件的顶级元素的顺序

单文件组件应该总是让<script>、<template> 和 <style> 标签的顺序保持一致。且 <style> 要放在最后,因为另外两个标签至少要有一个。
<!-- ComponentA.vue --> <template>...</template> <script>/* ... */</script> <style>/* ... */</style>

scoped 中的元素选择器

在 scoped 样式中,类选择器比元素选择器更好,因为大量使用元素选择器是很慢的
<template> <button class="btn btn-close">X</button> </template> <style scoped> .btn-close { background-color: red; } </style>

vue组件划分

页面组件的定义仅仅是整张页面的统筹,页面组件也是由一个个功能组件堆叠而成的

功能组件的定义为,他的展示只受父组件通过props组件传值过来的数据影响,他的所有状态均为内部私有,与外部组件的交互有vue提供的props以及事件分发vm.$emit()。因为只有这也组件才能保证其完整的内部状态,在复用时不受其他因素的影响。

划分页面组件最简单的方式是由路由划分,每一个路由对应一个页面组件。 功能组件的划分需要对页面组件的功能进行分析分类。功能组件的划分可能根据不同人的理解各不相同,但是原则只有一个:

功能组件应该类似面向对象编程一样,一个功能组件应该只是完成一个功能

页面组件是无法复用的组件,功能组件是可以复用的组件。

拿销项2.0 的布局来举个例子

功能组件可能有以下几个:

1. 顶部组件, 里边包含 , nav 组件, 下拉组件等

2. 左侧菜单组件:

3. table组件:

4. 分页组件:

5. 按钮组件:

6. 各种form 表单组件

7. 底部组件

文末彩蛋:VSCode拓展插件推荐(HTML、Node、Vue、React开发均适用)

https://github.com/varHarrie/varharrie.github.io/issues/10

vscode 相关配置

{ // 控制字体系列。 "editor.fontFamily": "Consolas, Courier New, monospace,宋体", // 以像素为单位控制字号。 "editor.fontSize": 18, // 控制选取范围是否有圆角 "editor.roundedSelection": false, // 建议小组件的字号 "editor.suggestFontSize": 16, // 在“打开的编辑器”窗格中显示的编辑器数量。将其设置为 0 可隐藏窗格。 "explorer.openEditors.visible": 0, // 是否已启用自动刷新 "git.autorefresh": false, // 是否启用了自动提取。 "git.autofetch": false, // 以像素为单位控制终端的字号,这是 editor.fontSize 的默认值。 "terminal.integrated.fontSize": 14, // 控制终端游标是否闪烁。 "terminal.integrated.cursorBlinking": true, // 一个制表符等于的空格数。该设置在 `editor.detectIndentation` 启用时根据文件内容进行重写。 "editor.tabSize": 2, // Tab Size "beautify.tabSize": 2 }

常用插件

Beautify;

git blame

git history

open in browser

vetur

vue 2 snippets

Vue VSCode Snippets

eslint

不好意思!耽误你的十分钟,让MVVM原理还给你 - 掘金