seho 发布的文章

此blog不是恰饭,主要是放美照的,嘻嘻

地点: 陕西商洛的金丝峡
票价: 成人是100¥/人
总体感觉:有峡谷也有山,完美,爬完山之后走峡谷乘凉,非常划算
注意事项:来这里一定要爬山,走峡谷就爬不了山,但是下山之后可以走峡谷
微信图片_20200510203750.jpg

微信图片_20200510203753.jpg

微信图片_20200510203756.jpg

微信图片_20200510203800.jpg

微信图片_20200510203803.jpg

微信图片_20200510203809.jpg

微信图片_20200510203812.jpg

微信图片_20200510203816.jpg

微信图片_20200510203818.jpg

微信图片_20200510203822.jpg

微信图片_20200510203825.jpg

微信图片_20200510203829.jpg

微信图片_20200510203834.jpg

微信图片_20200510203831.jpg

微信图片_20200510203837.jpg

微信图片_20200510203840.jpg

微信图片_20200510203844.jpg

微信图片_20200510203847.jpg

微信图片_20200510203850.jpg

微信图片_20200510203854.jpg

微信图片_20200510203856.jpg

微信图片_20200510203859.jpg

微信图片_20200510203903.jpg

微信图片_20200510203907.jpg

微信图片_20200510203910.jpg

微信图片_20200510203913.jpg

微信图片_20200510203916.jpg

微信图片_20200510203919.jpg

微信图片_20200510203923.jpg

微信图片_20200510203926.jpg

微信图片_20200510203933.jpg

微信图片_20200510203936.jpg

微信图片_20200510203939.jpg

美中不足的一件事情

在上山之后的当天早上就收到了外爷的死讯,几个月的煎熬安详地走了,第二天我就马不停蹄的回老家去参加外爷的丧事,这也是我第一次参加丧事,小时候有印象的参加了外婆的丧事,当时还很小就被妈妈抱上床,这边当地的习俗 “转香”也没有转,但是这次连续好几个晚上我都为外爷完成了祈祷,在入土的前一天我也见到了外爷,满足了我的心愿,愿他在天堂可以过得很好,愿他一直有好酒喝,愿他永远保持一个老小孩的心态

基于NPM的包或者库,项目中的package.json是对项目的描述,这个json对象中的script标签就是npm运行脚本,vue.js在这里配置了如下的内容

"build": "node build/build.js",
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer", (**注意这一块是用逗号分割的**)
"build:weex": "npm run build -- weex"

vue当然有很多script命令,但是仅仅只有这几种是build的,build:ssr和build:weex其实和build一样,只不过提供了不同的运行参数

查找build的入口文件,vue是如何做build源码的?

打开对应的build/build.js

let builds = require('./config').getAllBuilds()
// filter builds via command line arg
if (process.argv[2]) {
  const filters = process.argv[2].split(',') (**分割出来的数组是["web-runtime-cjs","web-server-renderer"]** )
 // 通过getAllBuild函数返回的config对象对其打包模式进行了rollup的配置,包括output等设置
 // 而下面这一段代码的b则是返回的config对象,filters这个参数数组使用some来判断builds中output中的file(被resolve函数定义了,这个resolve函数下面会具体讨论)
  builds = builds.filter(b => {
    return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1)
  })
} else {
  // filter out weex builds by default
  builds = builds.filter(b => {
    return b.output.file.indexOf('weex') === -1
  })
}

这一段代码其实非常简单,作者也在源码中写了注释解释了这段代码的作用

通过命令行arg构建过滤器

其中引入的config 文件调用了getAllBuilds这个方法,在config.js可以看出

 exports.getAllBuilds = () => Object.keys(builds).map(genConfig)

这一句代码是导出config的关键代码,builds是预定义的一些对象

 // runtime-only build (Browser)
  'web-runtime-dev': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.js'),
    format: 'umd',
    env: 'development',
    banner
  },
entry: 入口文件
dest: 输出目标文件
format: 构建的格式 umd为umd格式 cjs遵循commonJS规范 es遵循esmodule规范
env:开发模式/生产模式
banner指的是每个js的页头,比如作者,信息,开源协议等信息
还有其他的一些关于rollup(很像webpack的一些设计)别名诸如此类的配置,这边就不阐述了,因为我也忘记的差不多了,文档都很好查,想知道具体的意思也很容易

resolve函数的定义

这里的resolve函数比较简短,很容易理清

//假定一个config中使用resolve这个函数,它传递的字符串是这样的
'web-runtime-cjs': {
    entry: resolve('web/entry-runtime.js')
  }

const resolve = p => {
  const base = p.split('/')[0]
  if (aliases[base]) {
    return path.resolve(aliases[base], p.slice(base.length + 1))
  } else {
    return path.resolve(__dirname, '../', p)
  }
}

首先base则是 “web”这个字符串,
这个base并不是真实的路径,而这个web则指向了aliases的配置

module.exports = {
  web: resolve('src/platforms/web'),
}

这里的web指向的路径就是src/platforms/web
那么resolve函数返return的就是path.resolve,其中第一个参数就是web,第二个参数则是entry-runtime
所以由此得知,通过这样的一个过程找到了build的入口文件然后经过rollup的打包就会在dist目录下生成web/entry-runtime.js

拓展阅读

Runtime Only VS Runtime + Compiler 推荐阅读

在初级和中级前端面试笔试中,函数的防抖和节流要求候选人有能力去精通或者熟悉里面的机制,不仅仅要知道基本版的防抖和节流,还要知道更完美进阶的节流防抖,比如一些lodash中的实现等等,所以这个系列也是从基础版开始,我会和大家一起补充这方面的知识


配套代码地址在线调试和编辑
参考文章

防抖

【背景故事】
某商业楼每天早上上班高峰期的电梯非常堵,通常生活来讲,一个电梯肯定是要进去很多人的直到人满为止,这对于自身和电梯都是一种节约资源的表现,不可能出现每个人一人一个电梯的情况,所以对于电梯和我们,这是一种防抖函数的表现。

电梯每当停到一个楼层,会等我们进去,人没有塞满或者没有人它才会到达指定楼层。
在web端最容易遇到的就是input搜索,用户输入一个字符,会在指定的时间中监听是否还有字符进入,如果没有,那么就执行对应的函数,这样就解决了用户频繁输入字符而前端发起请求给服务器造成压力的问题
// 防抖函数
function debounce(fn, time = 300) {
  let timer = null;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, time);
  };
}

基础版的代码梳理,通过这个函数将fn传递,就能实现防抖的效果,当用户输入的第一个字符,会把timer函数赋予一个延时器,这个延时器执行了对应的fn,this是为了绑定执行的this指向,arguments则是这个函数的参数类数组对象,当用户在延时还未触发的时候再次输入字符,那么clearTimeout把上一个timer清除掉了,因为闭包的作用,timer不会被销毁,这样的一个函数就表示了,只要在延时间隔中(此时timer被赋值了),如果谁再调用此函数,会把上一个timer清空掉,重新延时,依次类推...

节流

【背景故事】
在0几年的时候包括可能现在都有,很多家庭知道水管把阀门开到最小,让水一滴一滴的掉下,是不会走水表的(不计费的),所以在我很小的时候就知道这个事情,虽然现在没有了,但是还是觉得很羞愧,节流函数就是起到的作用就是,把原本频繁的调用变得有秩序有间隔;

以监听scroll滚动为例:

// 节流函数
function throttle(fn, time = 300) {
  let canRun = true;
  return function() {
    if (!canRun) return;
    canRun = false;
    setTimeout(() => {
      fn.apply(this, arguments);
      canRun = true;
    }, time);
  };
}

$(window).on(
  "scroll",
  throttle(() => {
    console.log("触发了scroll");
  }, 300)
);

在这个函数中,canRun这个变量变化了3次,判断了一次如果为false就return掉

  1. 初始化时设置为true
  2. 判断canRun是否为false后设置了canRun为false
  3. 最终事件执行完毕之后设置canRun为true,否则就进入不了下一次的节流

其实这个函数从开始到结束的canRun形成了一次循环,这个循环唯一保证的就是只有事件结束才可以开始下一个事件

总结

节流:保证回调能在指定的时间间隔中依次有规律的执行
防抖:保证回调能在指定的时间间隔中等待是否有再次执行回调,如果没有则执行,如果有则重置继续等待;

我说我过年期间更新了3篇关于uniapp的文章,然后发布莫名消失,你们会信么?

timg.jpg

其实是真的,家里的网络非常不稳定,我连续发了2次文章,结果预览出来的效果仅仅只有一个自然段,剩余全部丢失,所以渐渐的我心态崩掉了,然后转眼就来到了4月,我仍然会每周坚持更新笔记/感悟,分享给大家。

这是一个全新的计划,关于分析vue的源码,那么我需要一个课程带着我学习,因为讲真,它有些门槛,像我第一次看底层源码,不知道从何看起,网上有太多的关于vue的实现,比如methods,computed实现,但是都太单一,所以我在youtube上找到课程,也是慕课网的金牌讲师ustbhuangyi

所以我会把这个课程参考的资料放到这个文章的顶部
他的博客,vue源码资料
正版课程,请大家看完一定要去购买支持正版,虽然我没购买
youtube免费课程,高清,可以翻墙免费看全集


这边配套的源码截止于目前文章发表的日期,版本是2.6.11,大家在学习vue源码的核心内容的时候,只要是2.0版本的最新的内容,基本上不会影响学习vue.js的灵魂。


首先来了解一下看到这个标题,这篇文章就简单的看一下vue的src源码中的目录分工,我们在写一般的vue工程时,也会分很多很多的文件进行模块化开发,这是大势所趋,比如api;common;util;components;assets;static;pages等等,那么在框架开发中,一般像我一样的初学者就很懵逼,所以我们一起来看看;

compiler

这是vue.js编译相关的代码,它包括把vue模板编译成AST抽象语法树,一般情况下,编译会在构建时进行,因为是很耗费时长的,像webpack或者vue-loader这样的插件;

core

这里的目录是vue.js的核心之处,我们所见到的2.0新特性的vdom,监听,状态,初始化,render等等都在这里

platforms

我们一般常用的vue.js是在web端,那么vue.js也支持编译成供weex这样的运行在native上的框架
这个目录就是vue.js针对不同的平台而编译的入口

server

vue.js支持服务端渲染内容,即这里的目录是在node中进行运行的,服务端运行将返回html字符串进行渲染,这里是在服务端的vue.js而不是web端的vue.js

sfc

这里的parser.js会把编写的.vue文件转换成js对象

shared

vue.js用到的公共的方法,它将是所有的目录公共可访问的内容


这两天会根据计划更新其他的内容,这个部分会一直进行下去,不定时更新

参考文档:
uniapp使用Weex/nvue的注意事项
weex官方文档
v3引擎更新文档
Nvue 首页快速启动模式文档

作为一个有一年经验的uniapp的开发者,自从脱坑老老实实做web前端,已经蛮久没有使用dcloud家的东西,由于今年的工作计划中,uniapp仍然占据着主导的地位,便老老实实的看看uniapp最近半年的更新文档,映入眼帘的就是v3引擎和一个fast极速启动的功能,下面会简单的提到我重新踩坑过程。

写在前面

本文需要一定的uniapp基础和必备的vue基础
在之前的开发中,并没有使用到nvue这个基于原生渲染的app页面,所以在计划中,nvue将会被app的组件/复杂计算较多的页面使用,采用vue+nvue结合的方式,所以我希望在功能开始之前,尝试一下所谓的v3引擎和fast启动有多么厉害

fast模式

fast模式必须使用v3引擎,它能够让app启动时视图层不再等待服务层加载完毕,即可以同时渲染,所以在启动fast模式时,能肉眼直观的感觉到此模式有多么的快速,但是在nvue首页请避免采用vuex和使用getApp()方法,因为service层此时不一定初始化完毕。

v3引擎

在之前的编译模式中,uniapp从最初的模板编译模式到之后的自定义组件模式,我在自定义组件模式尝到了很多甜头,在之前的业务中写过一个表单组件,很多的日期选择器和输入表单造成了输入的卡顿,所以就升级成了自定义组件模式就成功解决了问题,还有就是类似于电影院订座的页面,渲染了大量的dom造成了选中卡顿,采用了此模式也成功解决了性能上的问题,所以我准备花更多的心思研究了此次更新的模式:v3引擎

总结的常用优势有以下几项:

  1. 开发编译速度更快
  2. app运行更快
  3. 支持视图层调试
  4. 支持了更多的vue语法

这几项我最关心的是app运行时的流畅度,但是官方文档没有对这方面有测评说明,只能具体的在自己项目中感受了...

新增了部分的vue语法, 用的比较多的是filter和props中的特性:

微信截图_20200127151840.png

微信截图_20200127151917.png

使用nvue和weex

在hbuilder中有一个配置项是:纯nvue项目,如果勾选了可以加快app启动速度和减少包体积,但是为了更好的开发体验,全部用nvue写实在是一个噩梦,太多的特性在nvue中是不支持的,所以建议大家使用vue+nvue构造项目。

初次上手nvue发现了很多坑,以下我将把我遇到的部分问题结合文档阐述,如果想要更详细的兼容问题就去参考文档的第一个链接查看对应的内容。

官方文档里面有这样一句话:

如果你已经是 weex 的开发者,具有 weex 的填坑能力,那么 nvue 是你的更优选择,能切实提升你的开发效率,降低成本。
起初,我不以为然,到后来,css选择器,一些简写语法都编译不通过,使得一个简单的页面花了半天去填坑,所以weex是真的对我们写惯了web的人来说真的是很不友好呀。

nvue的编译模式区别

  1. uniapp
  2. weex

项目中选择的是uniapp编译模式;

  1. 因为它可以写这样的组件,即可以发布在微信小程序和h5中,但是如果是weex,就只能写
    只能编译到APP中。
  2. 因为它可以支持uniapp的生命周期,weex模式下只支持weex的生命周期
  3. 调用API时,它们都相同,weexAPI,uniappApi, plusApi都可以调用
  4. 最主要的就是跨端,weex只支持APP,而uniapp是跨所有端
提示:如果没有明确配置编译模式,默认是weex编译模式,因为要向下兼容;

配置方法:

// manifest.json    
{    
    "app-plus": {    
        "nvueCompiler":"uni-app"  uniapp/weex
    }    
}

出现了同名的vue文件,该怎么办?
如果nvue文件名和vue文件名出现了冲突,那么在app端会使用nvue的页面,vue页面不会被编译,反之亦然;那么如果只有一个nvue文件存在非app端,则要取决于nvue的编译模式,如果是uniapp端将会被编译,如果是weex不会被编译,因为weex编译模式不支持非app端

开发nvue的注意事项(老沈心态崩溃的开始)
模板:日常写法同vue一样,如果nvue模式是uniapp可以使用uniapp的组件(部分组件没有实现nvue)如果是weex模式,就如同weex组件的写法。

js:都是vue写法,支持weexAPI,uniappApi, plusApi这三种api方式,weexAPI需要按照模块引入的方式再调用API,uniappApi大部分都支持,小部分不支持调用,plusApi在自定义组件编译模式下可以自由使用,但是v3引擎下是否支持,官方文档暂未发现说明。

样式:这里加粗字体的原因是重点,nvue只支持flex布局,包括很多css都不支持,尤其是简写,举例子比如说是边框线,通常我们会这样写:

border: 1px solid red;

但是weex/nvue规定是这样的:

border-width: 1;
border-style: solid;
border-color: red;

nvue 和 vue 相互通讯
在vue和nvue页面混用的项目中,通讯是一个大问题,我认为的是直接路由传参即可和以前一样,但是没有我想象中那么简单;

nvue -> vue (data是键值对,值仅仅支持字符串)

  nvue中使用:    uni.postMessage(data); 
  vue中使用函数: onUniNViewMessage 监听

vue -> nvue

   vue中使用plus的方法:
   plus.webview.postMessageToUniNView(data,nvueId);
   参数说明: data同样是键值对,值必须是字符串, nvueId是nvue在webview中的id,可以通过
    $getAppWebview()获取到id

   在 nvue 里引用 globalEvent 模块监听 plusMessage 事件即可监听vue发送的数据

具体看这里的demo: vue向nvue传值的方法

vue和nvue共享的变量和数据

  • vuex(不支持直接引入store,要引入mapMutations等辅助方法或者this.$store;只支持uniapp编译模式,不支持weex编译模式;)
  • 存储storge(vue和nvue互相通讯可以使用这个,但是过于扯淡,这个存储是持久化的)
  • 小程序中有一个叫globalData的机制,从来没用过,从官方文档中了解的,操作如下:

         App.vue:
    
         globalData: {  
             text: 'text'  
         },  
         onLaunch: function() {  
             console.log('App Launch')  
         },  
         onShow: function() {  
             console.log('App Show')  
         },  
         onHide: function() {  
             console.log('App Hide')  
         }  
    

    在vue页面中使用: getApp().globalData.text就可以获取到值了,如果要在vue页面中绑定该值,在onShow钩子中变量再赋值即可,关于onShow机制有一些注意事项(从官方摘抄)

如果需要把globalData的数据绑定到页面上,可在页面的onShow声明周期里进行变量重赋值。HBuilderX
2.0.3起,nvue页面在uni-app编译模式下,也支持onShow。 weex编译模式不支持onShow,但熟悉5+的话,可利用监听webview的addEventListener
show事件实现onShow效果。

ok,介绍到此为止,常见的日常开发遇到的问题其实看我这一篇不会有太大问题,如果你遇到了其他问题可以来找我,我们一起讨论学习,或者你也可以看文章顶部的参考文章,也可以去那里去寻找你想要的答案噢~

祝大家新年快乐,出门记得戴口罩噢