Skip to content

Commit

Permalink
weex启动遇到的坑
Browse files Browse the repository at this point in the history
  • Loading branch information
liangklfangl committed Mar 14, 2018
1 parent f8c9d86 commit 3e72151
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@

[waterfull vs parallel vs series异步方法详解](./async-programing/async-js/readme.md)

##### 2.6 weex与vue部分

[关于vue文档的进一步细化](./vue/basic.md)

[weex遇到的那些坑](./weex/error.md)

#### 3.运行说明
对于每一个文件下都是一个单独的项目可以运行,你只要cd到这个目录下,运行下面的命令即可:

Expand Down
12 changes: 12 additions & 0 deletions js-native/foundamental-QA.md
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,16 @@ CSS样式为:
7.层叠级数大于等于1的“positioned”子层叠上下文,数值越小越早被绘制;
</pre>

##### 10.事件处理函数中的[passive:true](http://blog.csdn.net/shenlei19911210/article/details/70198771)配置
由于浏览器无法预先知道一个事件处理函数中会不会调用preventDefault(),它需要**等到事件处理函数执行完后,才能去执行默认行为**,然而事件处理函数执行是要耗时的,这样一来就会导致页面卡顿,可以动手试试,比如在事件处理函数里面写一个耗时的循环。

其实passive就是为此而生的。设置了passive:true的情况下,即使滚动事件里面写了一个死循环,浏览器也能够正常处理页面的滑动。在DOM的最新规范中,事件处理函数的第三个参数变成了一个对象:
```js
target.addEventListener(type, listener[, options]);
```
我们可以通过传递passive为true来明确告诉浏览器,事件处理程序不会调用preventDefault来阻止默认滑动行为。此时浏览器就能**快速生成事件(滚动事件)**,从而提升页面性能,而不用等待滚动事件处理完成后才触发。




参考资料:
Expand Down Expand Up @@ -1062,3 +1072,5 @@ CSS样式为:
[利用performance统计网站的加载新能](https://www.jianshu.com/p/5f3968a5e7ee)

[层叠上下文 Stacking Context](http://web.jobbole.com/83409/)

[移动端Web界面滚动性能优化: Passive event listeners](http://blog.csdn.net/shenlei19911210/article/details/70198771)
153 changes: 153 additions & 0 deletions vue/basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -802,8 +802,161 @@ export default {
```
插槽,也就是slot,**是组件的一块HTML模板**,这块模板显示不显示、以及怎样显示由父组件来决定。 实际上,一个slot最核心的两个问题这里就点出来了,是**显示不显示****怎样显示**

#### 17.Vue中的computed与watch
##### 17.1 为什么要引入计算属性
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
```html
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
```
在这个地方,模板**不再是简单的声明式逻辑**。你必须看一段时间才能意识到,这里是想要显示变量 message的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。所以,对于任何复杂逻辑,你都应当使用**计算属性**

##### 17.2 [计算属性的特点](https://cn.vuejs.org/v2/guide/computed.html)
```html
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
```
下面是组件:
```js
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
```
(1)我们已经以声明的方式创建了这种依赖关系:计算属性的getter函数是**没有副作用** (side effect) 的,这使它更易于测试和理解。**watch**选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

(2)计算属性是**基于依赖进行缓存**的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 message还没有发生改变,多次访问reversedMessage计算属性会立即返回之前的计算结果,而不必再次执行函数。但是如果在模板中直接`调用方法`,那么结果并不会缓存。同时也需要注意:计算属性也是可以提供setter方法的。


#### 18.Vue中的过滤器
Vue.js允许你自定义过滤器,**可被用于一些常见的文本格式化**。过滤器可以用在两个地方:**双花括号插值****v-bind 表达式** (后者从 2.1.0+ 开始支持)。过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示:
```js
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!--`v-bind`-->
<div v-bind:id="rawId | formatId"><\/div>
```
添加过滤器可以通过如下两种方式来完成,包括`本地过滤器`和全局过滤器:
```js
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
```
`全局过滤器`可以通过如下方法定义:
```js
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
})
```

#### 19.Vue的响应式原理
当你把一个普通的JavaScript对象传给Vue实例的data选项,Vue将遍历此对象所有的属性,并使用 **Object.defineProperty**把这些属性全部转为getter/setter。Object.defineProperty 是 ES5中一个无法shim的特性,这也就是为什么Vue不支持 IE8 以及更低版本浏览器的原因。用户看不到getter/setter,但是在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化。

**每个组件实例都有相应的watcher实例对象**,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher 重新计算,从而致使它关联的组件得以更新。

![](./images/watcher.png)

受现代JavaScript的限制 (以及废弃 Object.observe),Vue不能检测到对象属性的添加或删除。由于Vue会在初始化实例时对属性执行 getter/setter 转化过程,所以**属性必须在data对象上存在才能让Vue转换它,这样才能让它是响应的**。例如:
```JS
var vm = new Vue({
data:{
a:1
}
})
// `vm.a` 是响应的
vm.b = 2
// `vm.b` 是非响应的
```
Vue**不允许在已经创建的实例上动态添加新的根级响应式属性**(root-level reactive property)。然而它可以使用Vue.set(object, key, value)方法将响应属性添加到嵌套的对象上:
```js
Vue.set(vm.someObject, 'b', 2)
```
您还可以使用vm.$set实例方法,这也是全局Vue.set方法的别名:
```js
this.$set(this.someObject,'b',2);
```
有时你想向已有对象上添加一些属性,例如使用Object.assign()或 \_.extend()方法来添加属性。但是,添加到对象上的新属性不会触发更新。在这种情况下可以创**建一个新的对象**,让它包含原对象的属性和新的属性:
```js
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
```

#### 20.Vue[异步更新队列](https://cn.vuejs.org/v2/guide/reactivity.html)
可能你还没有注意到,Vue异步执行 DOM 更新。只要观察到数据变化,Vue将**开启一个队列,并缓冲在同一事件循环中发生的所有数据改变**。如果同一个 watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM操作上非常重要。然后,在下一个的事件循环“tick”中,Vue刷新队列并执行实际 (已去重的) 工作。Vue在内部尝试对异步队列使用原生的 Promise.then 和 MessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0) 代替。

例如,当你设置vm.someData = 'new value',该组件**不会立即重新渲染**。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况我们不需要关心这个过程,但是如果你想在DOM状态更新后做点什么,这就可能会有些棘手。虽然Vue.js通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触DOM,但是有时我们确实要这么做。为了在数据变化之后等待Vue完成更新DOM,可以在数据变化之后立即使用Vue.nextTick(callback)。**这样回调函数在DOM更新完成后就会调用**。例如:
```js
<div id="example">{{message}}<\/div>
var vm = new Vue({
el: '#example',
data: {
message: '123'
}
})
vm.message = 'new message' ;
// 更改数据
vm.$el.textContent === 'new message';
// false
Vue.nextTick(function () {
vm.$el.textContent === 'new message'
// true
})
```
在组件内使用[vm.$nextTick()](https://www.zhihu.com/question/50879936)实例方法特别方便,因为它不需要全局Vue ,并且回调函数中的this将自动绑定到当前的Vue实例上:
```js
Vue.component('example', {
template: '<span>{{ message }}</span>',
data: function () {
return {
message: '没有更新'
}
},
methods: {
updateMessage: function () {
this.message = '更新完成'
console.log(this.$el.textContent) // => '没有更新'
this.$nextTick(function () {
console.log(this.$el.textContent) // => '更新完成'
})
}
}
})
```
关于Vue异步更新的原理你可以[查看](https://www.zhihu.com/collection/226172852)这个文章。

#### Vue 中如何使用 MutationObserver 做批量处理?
https://www.zhihu.com/question/55364497/answer/144215284




参考资料:

[Vue.js 定义组件模板的七种方式](https://www.w3cplus.com/vue/seven-ways-to-define-a-component-template-by-vuejs.html)

[深入理解vue中的slot与slot-scope](https://segmentfault.com/a/1190000012996217)

[Vue中你不知道但却很实用的黑科技](https://div.io/topic/1880)

[你不知道的Vuejs - 深入浅出响应式系统](https://juejin.im/post/5a744fd06fb9a0634051e28f)

Binary file added vue/images/watcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 74 additions & 0 deletions weex/error.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#### 前言
下面是在weex中遇到的部分报错问题,特此记录下来,如果有用,拿走不谢。也欢迎start。

#### 1.weex版本不匹配导致的问题
报错信息如下:
<pre>
Users/qinliang.ql/Desktop/yk-message-center/node_modules/[email protected]@webpack/lib/TemplatedPathPlugin.js:50
if(!allowEmpty) throw new Error("Path variable " + match + " not implemented in this context: " + input);
^

Error: Path variable [name] not implemented in this context: /Users/qinliang.ql/.weex_tmp/[name].weex.js
at /Users/qinliang.ql/Desktop/yk-message-center/node_modules/[email protected]@webpack/lib/TemplatedPathPlugin.js:50:26
</pre>
解决方法:重新安装weex-toolkit:
```shell
npm uninstall weex-toolkit -g
# 必须uninstall一下
npm install weex-toolkit -g
```
安装后的版本为:
<pre>
- weex-debugger : v1.0.0-rc.32
- weex-builder : v0.3.17
- weex-previewer : v1.4.8
</pre>

#### 2.运行weex compile的时候babel-core不存在
报错信息如下:
<pre>
file:///usr/local/lib/node_modules/weex-toolkit/node_modules/[email protected]@babel-loader/lib/index.js

when use command weex compile case error /node_modules/weex-ui/index.js Module build failed: Error: Cannot find module 'babel-core'
</pre>
其实上面的报错信息很明显,说usr/local/lib/node_modules目录下的weex-toolkit的node_modules下不存在babel-core,有点绕(但是是全局安装的命令),解决方案如下:
```shell
cd /usr/local/lib/node_modules/weex-toolkit
# 最新的weex脚手架weex-toolkit竟然会出现这个问题,有点失望。
# 应该是weex-toolkit把babel-core设置为devDependencies依赖了导致未安装
# https://github.com/weexteam/weex-toolkit/blob/master/package.json#L28
tnpm i babel-core -S
```
这样当你运行`weex preview ./index.vue`的时候就不会出现问题了。

#### 3.weex preview命令的时候提示端口被占用
报错信息如下:
<pre>
weex preview ./index.vue
09:48:55 : Bundling source...
09:48:56 : weex JS bundle saved at /Users/qinliang.ql/.weex_tmp
09:48:57 : Wed Mar 14 2018 09:48:57 GMT+0800 (CST)WebSocket is listening on port 8082
09:48:57 : Wed Mar 14 2018 09:48:57 GMT+0800 (CST)http is listening on port 8081
09:48:57 : http://30.97.92.166:8081/?hot-reload_controller&page=index.js&loader=xhr&wsport=8082&type=vue
09:48:57 : Error: listen EADDRINUSE 0.0.0.0:8082
at Object._errnoException (util.js:1022:11)
at _exceptionWithHostPort (util.js:1044:20)
at Server.setupListenHandle [as _listen2] (net.js:1351:14)
at listenInCluster (net.js:1392:12)
at doListen (net.js:1501:7)
at _combinedTickCallback (internal/process/next_tick.js:141:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
09:48:57 : The server has been setted up.

</pre>

我马上执行了下面的命令:
```shell
lsof -i:8082
# 我发现8082根本就没有被占用,如果占用可以使用kill -9 (pid的值)
```
因为以前以尝试开发过cli命令,所以我自然想到指定--port,抱着试一试的心态:
```shell
weex preview ./index.vue --port 8088
```
此时发现一切正常。

0 comments on commit 3e72151

Please sign in to comment.