Skip to content

Commit 8c7cf35

Browse files
committed
add vue开发技巧
1 parent ce3751a commit 8c7cf35

File tree

3 files changed

+253
-32
lines changed

3 files changed

+253
-32
lines changed

images/vue/1575336533.jpg

107 KB
Loading

images/vue/1575352877.jpg

7.05 KB
Loading

vue/vue开发技巧.md

+253-32
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#### 一键生成.vue文件模板
1+
### 一键生成.vue文件模板
22

33
我们借用vscode自带的功能
44

@@ -48,7 +48,9 @@
4848

4949

5050

51-
#### 重置data或者获取data初始值
51+
### 重置data或者获取data初始值
52+
53+
在某些情况我们可能要重置data上面的某些属性
5254

5355
```javascript
5456
this.$data //获取当前状态的data
@@ -58,7 +60,7 @@ Object.assign(this.$data,this.$options.data()) //重置data
5860

5961

6062

61-
#### 强制刷新组件
63+
### 强制刷新组件
6264

6365
```javascript
6466
this.$forceUpdate() //迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
@@ -80,7 +82,21 @@ key++;
8082

8183

8284

83-
#### 长列表优化
85+
### performance[文档](https://cn.vuejs.org/v2/api/#performance)
86+
87+
进行组件初始化、编译、渲染和打补丁的性能追踪
88+
89+
```javascript
90+
//main.js
91+
const isDev = process.env.NODE_ENV !== "production";
92+
Vue.config.performance = isDev;
93+
```
94+
95+
![img](../images/vue/1575336533.jpg)
96+
97+
98+
99+
### 长列表优化
84100

85101
当我们遇到很多的数据展示且不需要响应式变化时,我们就可以使用[Object.freeze](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)进行优化;
86102

@@ -89,25 +105,113 @@ key++;
89105
当我们把一个对象传给实例的data,Vue会使用`Object.defineProperty`把这些属性响应式,使用了 [Object.freeze](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)之后,不仅可以减少 `observer` 的开销,还能减少不少内存开销,Vue有人提了相关[issue](https://github.com/vuejs/vue/issues/4384)
90106

91107
```javascript
92-
this.list = Object.freeze(Object.assign({}, this.list))
108+
export default {
109+
data(){
110+
return {
111+
list: []
112+
}
113+
},
114+
async created() {
115+
const list = await this.$axios.get("/goodsList");
116+
this.list = Object.freeze(list);
117+
}
118+
};
119+
93120
```
94121

95122

96123

97-
#### $attrs和$listeners的使用场景
124+
### $attrs & $listeners
125+
126+
我们平时组件传值props跟emit用的比较多,但是有些时候他们不是父子组件就比较麻烦了
127+
128+
现在三个嵌套的组件, A -> B -> C ,我们现在要从A传值给C, 或者C通过emit传值给A
129+
130+
![img](C:\Users\Administrator\Desktop\txw\note\images\vue\1575352877.jpg)
131+
132+
A组件
133+
134+
```vue
135+
<template>
136+
<div>
137+
<B :name="name" @changeName="changeName"/>
138+
</div>
139+
</template>
140+
141+
<script>
142+
import B from './B'
143+
export default {
144+
components: {
145+
B
146+
},
147+
data () {
148+
return {
149+
name:'蜡笔小新'
150+
}
151+
},
152+
methods: {
153+
changeName(msg){
154+
this.name = msg
155+
}
156+
}
157+
}
158+
</script>
159+
160+
```
161+
162+
B组件
163+
164+
```vue
165+
<template>
166+
<div>
167+
<C v-bind="$attrs" v-on="$listeners"/>
168+
</div>
169+
</template>
170+
<script>
171+
import C from './C'
172+
export default {
173+
components: {
174+
C
175+
},
176+
}
177+
</script>
178+
179+
```
180+
181+
C组件
182+
183+
```vue
184+
<template>
185+
<div>
186+
{{name}}
187+
<button @click="changeName">修改</button>
188+
</div>
189+
</template>
190+
<script>
191+
export default {
192+
props:{
193+
// A组件传来的
194+
name:{
195+
type:String
196+
}
197+
},
198+
methods: {
199+
changeName(){
200+
this.$emit('changeName','coder') //传给A组件
201+
}
202+
}
203+
}
204+
</script>
98205
99-
```javascript
100-
A -> B -> C
101-
$attrs //跨组件传值 A传值给C 在B组件上写上 v-bind="$attrs"
102-
$listeners //跨组件执行事件 在C执行emit传值给A组件 在B组件上写上 v-on="$listeners"
103-
一般在对UI组件进行二次封装时,只写上常用的一些属性跟方法,然后写上$attrs和$listners,我们使用组件时就可以直接使用原组件的属性跟方法
104206
```
105207

208+
这样我们就实现了跨组件传值,一般在对UI组件进行二次封装时,只写上常用的一些属性跟方法,然后写上$attrs和$listners,我们使用组件时就可以直接使用原组件的属性跟方法
209+
106210

107211

108-
#### .sync修饰符
212+
### .sync修饰符
109213

110-
因为vue带来的双向绑定给开发带来了便利,同时也带来了代码维护上的问题,我们可以在子组件直接修改父组件穿的prop,新版本直接修改会报warn,推荐以 `update:myPropName` 的模式触发事件取而代之
214+
因为vue带来的双向绑定给开发带来了便利,同时也带来了代码维护上的问题,我们可以在子组件直接修改父组件穿的prop,新版本直接修改会报warn,官方推荐以 `update:myPropName` 的模式触发事件取而代之
111215

112216
```vue
113217
<text-document v-bind:title.sync="msg"></text-document>
@@ -118,7 +222,84 @@ $listeners //跨组件执行事件 在C执行emit传值给A组件 在B组件上
118222
this.$emit('update:title', newTitle)
119223
```
120224

121-
#### 自定义组件的 `v-model` [文档](https://cn.vuejs.org/v2/guide/components-custom-events.html#自定义组件的-v-model)
225+
226+
227+
### hook
228+
229+
这是一个文档中没有的api,在源码中存在的,我们可以看vue源码_init函数中是通过callHook调用生命周期的
230+
231+
```javascript
232+
vm._self = vm;
233+
initLifecycle(vm);
234+
initEvents(vm);
235+
initRender(vm);
236+
callHook(vm, 'beforeCreate');
237+
initInjections(vm); // resolve injections before data/props
238+
initState(vm);
239+
initProvide(vm); // resolve provide after data/props
240+
callHook(vm, 'created');
241+
```
242+
243+
然后我们找到callHook,我们可以看到vm._hasHookEvent为true时就会执行 vm.$emit('hook:' + hook)
244+
245+
```javascript
246+
function callHook (vm, hook) {
247+
// #7573 disable dep collection when invoking lifecycle hooks
248+
pushTarget();
249+
var handlers = vm.$options[hook];
250+
var info = hook + " hook";
251+
if (handlers) {
252+
for (var i = 0, j = handlers.length; i < j; i++) {
253+
invokeWithErrorHandling(handlers[i], vm, null, vm, info);
254+
}
255+
}
256+
if (vm._hasHookEvent) {
257+
vm.$emit('hook:' + hook);
258+
}
259+
popTarget();
260+
}
261+
```
262+
263+
然后我们通过`_hasHookEven`t找到相关代码,当通过$on去监听时,如果事件名以 hooks: 作为前缀,vm._hasHookEvent就会被置为true
264+
265+
```javascript
266+
var hookRE = /^hook:/;
267+
Vue.prototype.$on = function (event, fn) {
268+
var vm = this;
269+
if (Array.isArray(event)) {
270+
for (var i = 0, l = event.length; i < l; i++) {
271+
vm.$on(event[i], fn);
272+
}
273+
} else {
274+
(vm._events[event] || (vm._events[event] = [])).push(fn);
275+
// optimize hook:event cost by using a boolean flag marked at registration
276+
// instead of a hash lookup
277+
if (hookRE.test(event)) {
278+
vm._hasHookEvent = true;
279+
}
280+
}
281+
return vm
282+
};
283+
```
284+
285+
使用场景
286+
287+
```javascript
288+
mounted(){
289+
let i = 0
290+
this.timer = setInterval(()=>{
291+
console.log(++i);
292+
},1000)
293+
294+
this.$on('hook:beforeDestroy',()=>{
295+
clearInterval(this.timer)
296+
})
297+
}
298+
```
299+
300+
301+
302+
### 自定义组件的 `v-model` [文档](https://cn.vuejs.org/v2/guide/components-custom-events.html#自定义组件的-v-model)
122303

123304
一个组件上的 `v-model` 默认会利用名为 `value` 的 prop 和名为 `input` 的事件,但是像单选框、复选框等类型的输入控件可能会将 `value` 特性用于[不同的目的](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#Value)`model` 选项可以用来避免这样的冲突:
124305

@@ -145,9 +326,11 @@ Vue.component('base-checkbox', {
145326
<base-checkbox v-model="lovingVue"></base-checkbox>
146327
```
147328

148-
这里的 `lovingVue` 的值将会传入这个名为 `checked` 的 prop。同时当 `触发一个 `change` 事件并附带一个新的值的时候,这个 `lovingVue` 的属性将会被更新。
329+
这里的 `lovingVue` 的值将会传入这个名为 `checked` 的 prop。同时当 触发一个` change`事件并附带一个新的值的时候,这个 `lovingVue` 的属性将会被更新。
330+
331+
149332

150-
#### 自动引入route文件
333+
### 自动引入route文件
151334

152335
当我们项目比较大的时候,我们就会把路由文件根据不同的业务模块拆分
153336

@@ -191,7 +374,7 @@ export default new Router({
191374

192375

193376

194-
#### 更新缓存的组件
377+
### 更新缓存的组件
195378

196379
使用vue的生命周期函数[activated](https://cn.vuejs.org/v2/api/#activated)
197380

@@ -202,11 +385,9 @@ export default new Router({
202385

203386

204387

388+
### watch的高级用法
205389

206-
207-
#### watch的高级用法
208-
209-
1.当我们watch一个值时,第一次不会指向,只有值发生变化时才会执行,此时需要我们将immediate设为true
390+
1.当我们watch一个值时,第一次不会执行,只有值发生变化时才会执行,此时需要我们将immediate设为true
210391

211392
2.普通的watch方法无法无法监听对象内部属性的改变,我们把deep设为true时就能进行深度监听了
212393

@@ -229,7 +410,7 @@ new Vue({
229410

230411

231412

232-
#### 异步数据传值给子组件
413+
### 异步数据传值给子组件
233414

234415
这是新手都会遇到的问题,父组件异步获取数据传给子组件,子组件拿不到值,下面是我平时的解决方案
235416

@@ -245,13 +426,46 @@ or
245426

246427

247428

248-
#### 巧用slot
429+
### 巧用slot
249430

250-
插槽是一个很好用的api
431+
插槽是一个很好用的api,特别是在封装组件的时候,让组件有更多扩展的空间
432+
433+
```html
434+
//封装通用header组件
435+
<template>
436+
<div class="cc-header header">
437+
<cc-svg-icon
438+
@click="goback"
439+
icon-class="left-arrow"
440+
class-name="left-arrow"
441+
size=".2rem"
442+
></cc-svg-icon>
443+
<div v-if="$slots.center" class="cc-header-center">
444+
<slot name="center"></slot>
445+
</div>
446+
<p class="cc-header-title" v-else>{{title}}</p>
447+
<div class="cc-header-right">
448+
<slot name="right"></slot>
449+
</div>
450+
</div>
451+
</template>
452+
```
453+
454+
```html
455+
//使用组件
456+
<cc-header>
457+
<template slot="center">
458+
<van-search class="search-input" placeholder="通用名" v-model="params.search" />
459+
</template>
460+
<template slot="right">
461+
<div class="search-btn" @click="toSearch">搜索</div>
462+
</template>
463+
</cc-header>
464+
```
251465

252466

253467

254-
#### 开发插件
468+
### 开发插件
255469

256470
Vue.js 的插件应该暴露一个 `install` 方法。这个方法的第一个参数是 `Vue` 构造器,第二个参数是一个可选的选项对象:
257471

@@ -292,7 +506,7 @@ Vue.use(MyPlugin)
292506

293507

294508

295-
#### ref
509+
### ref
296510

297511
`ref` 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 `$refs` 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
298512

@@ -305,15 +519,22 @@ Vue.use(MyPlugin)
305519

306520

307521

308-
#### hook
522+
### 一些不常用却很牛逼的api
309523

310-
这是一个文档中没有的api
524+
##### [Vue.observable( object )](https://cn.vuejs.org/v2/api/#Vue-observable)
311525

312-
#### 一些不常用却很牛逼的api
526+
让一个对象可响应。Vue 内部会用它来处理 `data` 函数返回的对象。当我们项目没使用vuex时,就可以使用这个api
313527

314-
##### [Vue.observable( object )](https://cn.vuejs.org/v2/api/#Vue-observable)
528+
```javascript
529+
import Vue from 'vue'
530+
export const store = Vue.observable({ count: 0 })
531+
export const mutations = {
532+
setCount (count) {
533+
store.count = count
534+
}
535+
}
315536

316-
让一个对象可响应。Vue 内部会用它来处理 `data` 函数返回的对象。
537+
```
317538

318539
##### [v-pre](https://cn.vuejs.org/v2/api/#v-pre)
319540

@@ -352,4 +573,4 @@ Vue.use(MyPlugin)
352573

353574
#### 总结
354575

355-
学习技术就是多水群多刷掘金,你就会知道自己多菜!!!!!然后偷偷去学习大神的技术
576+
学习技术就要多刷掘金,你就会知道自己多菜!!!!!然后偷偷去学习大神的技术

0 commit comments

Comments
 (0)