【轉載】騰訊2016公司代碼報告總結

2016年騰訊公司代碼報告已經正式發佈,記錄下開發過程當中遇到的問題,以及一些使用過的東西。
查看請微信掃碼:php


騰訊2016公司代碼報告前端篇

1.使用gulp來開發自動化。在開發中,咱們會遇到不少重複性的工做,好比更新代碼後刷新瀏覽器、壓縮圖片、壓縮js、編譯sass等等。gulp可使這些重複性的工做都幫你幹了。gulp的使用能夠參見gulp官網。 貼出下我使用的gulp腳本(註釋不少,一目瞭然)。css

var gulp = require('gulp');
// sass 插件
var sass = require('gulp-sass');
// 自動同步瀏覽器插件
var browserSync = require('browser-sync');
// 合併文件的插件
var useref = require('gulp-useref');
// 壓縮js插件
var uglify = require('gulp-uglify');
var gulpIf = require('gulp-if');
// 壓縮css插件
var cssnano = require('gulp-cssnano');
// 壓縮圖片插件
var imagemin = require('gulp-imagemin');
// 壓縮png圖片的插件
var pngquant = require('imagemin-pngquant');
// 緩存插件,能夠加快編譯速度
var cache = require('gulp-cache');
// 刪除文件插件
var del = require('del');
// 同步運行任務插件
var runSequence = require('run-sequence');
// 給css3屬性添加瀏覽器前綴插件
var autoprefixer = require('gulp-autoprefixer');
// sourcemap 插件
var sourcemaps = require('gulp-sourcemaps');
var lazypipe = require('lazypipe');
// 合成sprite圖片插件
var spritesmith = require('gulp.spritesmith');
var imageminOptipng = require('imagemin-optipng');
// 編譯sass文件,添加css3屬性瀏覽器前綴,reload 瀏覽器
gulp.task('sass', function () {
 return gulp.src('./src/scss/**/*.scss')
     .pipe(sass())
     .pipe(autoprefixer())
     .pipe(gulp.dest('./src/css'))
     .pipe(browserSync.reload({stream: true}));
});
// 自動更新瀏覽器任務
gulp.task('browserSync', function () {
 browserSync.init({
     server: {
         baseDir: 'src'
     }
 })
});
// 合併文件任務
// 在html設置須要合併的文件:
//  <!--build:js js/flexible.min.js -->
//      <script src="js/flexible_css.js"></script>
//      <script src="js/flexible.js"></script>
//  <!-- endbuild-->
// 執行任務後,會編譯成 : <script src="js/flexible.min.js"></script>
// 同時會把 flexible_css.js 和 flexible.js 合併成 flexible.min.js
gulp.task('useref', function () {
 return gulp.src('./src/*.html')
     .pipe(useref({}, lazypipe().pipe(sourcemaps.init, { loadMaps: true })))
     .pipe(gulpIf('*.js', uglify()))
     .pipe(gulpIf('*.css', cssnano()))
     .pipe(sourcemaps.write('maps'))
     .pipe(gulp.dest('dist'));
});
// 圖片壓縮任務
gulp.task('images', function () {
 return gulp.src('./src/img/**/*.+(png|jpg|gif|svg)')
     .pipe(imagemin({
         progressive: true,
         svgoPlugins: [{removeViewBox: false}],
         use: [pngquant()]
     }))
     .pipe(gulp.dest('dist/img'));
});
// 合併sprite圖任務
gulp.task('sprite', function () {
 var spriteData = gulp.src('./src/img/sprite/**/*.png')
     .pipe(spritesmith({
         imgName: 'sprite.png',
         cssName: 'sprite.scss',
         imgPath: '../img/sprite/sprite.png',
         cssFormat: 'scss',
         padding: 10
     }));
 return spriteData.pipe(gulp.dest('./src/img/sprite/'))
});
// 刪除build目錄
gulp.task('clean:dist', function () {
 return del.sync('dist');
});
// 清除緩存
gulp.task('cache:clear', function (cb) {
 return cache.clearAll(cb)
});
// 監控任務,當有sass文件,html文件,js文件改動的時候,刷新瀏覽器
gulp.task('watch', ['browserSync', 'sass'], function () {
 gulp.watch('./src/scss/**/*.scss', ['sass']);
 gulp.watch('./src/*.html', browserSync.reload);
 gulp.watch('./src/js/**/*.js', browserSync.reload);
});
// 構建最終輸出文件
gulp.task('build', function (callback) {
 runSequence('clean:dist', ['sass', 'useref', 'images', 'fonts'], callback);
});
// gulp 默認執行任務
gulp.task('default', function (callback) {
 runSequence(['sass', 'browserSync', 'watch'], callback);
});
 

 

2.在開發移動端頁面的時候,咱們須要兼容各類機型,iphone的機型相對來講比較少,可是android的機型倒是多種多樣,若是按照之前pc上開發頁面的經驗使用px來開發,確定會遇到各類兼容問題。雖然能夠用media query來適配,可是這種適配將是一個很是繁瑣的事情。那有沒有更好的解決辦法呢?固然是有的。在這裏推薦淘寶的可伸縮佈局方案 lib-flexible
實現原理見: https://github.com/amfe/article/issues/17
須要注意的地方是: 在設置字體的時候須要根據dpr來調整字體大小(若是不設置會致使dpr高的手機由於縮放係數小而致使文字在手機上看起來很小)。以下代碼所示:html

[data-dpr="1"] .preloader,[data-dpr="1"] .swiper-slide  {
  font-size: 18px;
}

[data-dpr="2"] .preloader,[data-dpr="2"] .swiper-slide  {
  font-size: 36px;
}
[data-dpr="2.5"] .preloader,[data-dpr="2.5"] .swiper-slide {
  font-size: 45px;
}
[data-dpr="2.75"] .preloader,[data-dpr="2.75"] .swiper-slide {
  font-size: 49px;
}
[data-dpr="3"] .preloader,[data-dpr="3"] .swiper-slide {
  font-size: 64px;
}
[data-dpr="4"] .preloader,[data-dpr="4"] .swiper-slide {
  font-size: 72px;
}

 

3.爲了更快的呈現頁面,頁面使用到的圖片第一時間並不加載,而是在預加載界面才加載圖片,固然同時也能夠加載js和其餘多媒體文件等。你們能夠在網上找到一些預加載的開源組件,或者本身寫一個預加載的組件。前端

 

4.爲了減小http請求數,能夠把一些小的圖片合併成一張雪碧圖。默認spritesmith 生成的雪碧圖代碼是經過像素來定位的。可是咱們頁面使用的rem。若是使用默認生成的雪碧圖代碼會致使圖片顯示並不完整。解決辦法是經過background-position 百分比來實現。具體實現原理參見:移動端適配之雪碧圖(sprite)背景圖片定位
本身寫了一個sass方法來把spritesmith生成的sass代碼轉換爲background-position的實現。以下:android

//spritesmith  生成的sprite.sass,主要是須要獲取到sprite圖片中各圖片的大小,用來計算background-position的值。大概以下代碼所示:
 $cloud-b: (686px, 0px, -686px, 0px, 800px, 306px, 1486px, 1173px, '../img/sprite/sprite.png', 'cloud-b', );

// sass方法

$base: 72px;
@function rem($size) {
  $remSize: $size / $base;
  @return #{$remSize}rem;
}
@mixin bgPostion($sprite){
  $iconX:nth($sprite, 1);
  $spriteWidth:nth($sprite, 7);
  $iconWidth:nth($sprite, 5);
  $iconY:nth($sprite, 2);
  $spriteHeight:nth($sprite, 8);
  $iconHeight:nth($sprite, 6);
  $x:0;
  $y:0;
  @if $iconX != 0{
    $x: ($iconX / ($spriteWidth - $iconWidth)) * 100%;
  }
  @if $iconY != 0{
    $y: ($iconY / ($spriteHeight - $iconHeight)) * 100%;
  }
  background-position: ( $x $y );
}
@mixin bg($sprite){
  $sprite-width:nth($sprite, 7);
  $sprite-height:nth($sprite, 8);
  background: transparent;
  background-repeat: no-repeat;
  background-size: rem($sprite-width), rem($sprite-height);
  width: rem(nth($sprite, 5));
  height: rem(nth($sprite, 6));
  @include bgPostion($sprite);
}

經過使用@include bg($cloud-b); 就能夠引入sprite圖片中相應的圖片了。css3

注意點: 在默認生成的sprite圖片中各個小圖片之間是沒有間隔的。這致使使用上面的方法的時候在部分機型上會多顯示1像素旁邊圖片的邊框。解決辦法是在生成sprite圖片的時候參數設置padding值:git

gulp.task('sprite', function () {
    var spriteData = gulp.src('./src/img/sprite/**/*.png')
        .pipe(spritesmith({
            imgName: 'sprite.png',
            cssName: 'sprite.scss',
            imgPath: '../img/sprite/sprite.png',
            cssFormat: 'scss',
            padding: 10
        }));
    return spriteData.pipe(gulp.dest('./src/img/sprite/'))
});

 

在使用幀動畫sprite圖的時候,能夠設置下圖片排列算法,好比說橫向排練,這樣在使用的時候也比較方便。algorithm: 'left-right'github

 

5.在實現吹風的動畫時,具體請看報告第三頁,使用了svg來實現。主要是使用path的 stroke-dasharray 和stroke-dashoffset屬性。原理能夠參考帥氣的SVG路徑描邊動畫 (path animation) 實戰應用](https://segmentfault.com/a/1190000007811310)
不過在實現的時候,咱們不僅僅須要風出現也須要風消失。實現的代碼以下:web

.cls-wind{
      // 省略其餘代碼
      stroke-dasharray: 100px;
      stroke-dashoffset: 120px;
      animation:  winds 2s ease infinite;
    }
@keyframes winds{
      from{
        stroke-dashoffset: 120px;
      }
      50%{
        stroke-dashoffset: 0;
      }

      to{
        stroke-dashoffset: -90px;
      }
}

 

注意點: 在使用AI或者PS生成svg圖像的時候,生成的文件會有不少多餘的信息。能夠利用svgo 來處理多餘的信息,圖像的文件尺寸會減小不少。在這也提一下圖片壓縮,移動端流量是很寶貴的,圖片的尺寸在保證效果的狀況下越小越好,可是我在使用過程當中發現imagemin 的壓縮效果並非很是理想,雖然能夠壓縮一點,可是效果不明顯。後面使用tinypng 壓縮對比的時候,發現tinypng的壓縮效果很是好,通常都能壓縮個50%的大小,而且壓縮後的圖片在手機上的表現肉眼幾乎看不出來。因此,我的建議在正式發佈的時候,使用tinypng把你須要使用到的圖片都壓縮一遍。算法

 

6.在使用css3動畫的時候,咱們應該儘可能避免瀏覽器的reflow,reflow會針對整個頁面進行重排,比較耗費性能。在實現報告中報告內容下拉的效果時,一開始使用的變換元素的height來實現。代碼大概以下:

@keyframes conten-action{
  from{
    height:0;
  }
  to{
    height:5rem;
  }
}

可是這樣在一些低端的機型上表現不是很好。後面換成經過變換background-size 來實現,能夠明顯的感受到在那些低端的機型上動畫流暢了不少。代碼大概以下:

@keyframes content-action{
       from{
          background-size: 100% 0%;
          opacity: 0;
        }
        20%{
          background-size: 100% 20%;
          opacity: 0;
        }
        to{
          background-size: 100% 100%;
          opacity: 1;
        }
}

固然css3的動畫性能優化還有不少其餘方面能夠探索。我這就只記錄我碰到的狀況了。

 

7.在報告最後一頁,會有一個火箭發射的效果。一開始想使用css3來實現,後面討論說使用css3工做量太大了,可使用視頻來播放這個動畫,如今已經有不少h5頁面是用視頻來實現的,說明視頻方案已是很成熟了。
咱們目前只支持微信端,這裏說明的狀況都是針對微信的狀況。
如今微信都已經支持了video的playsinline屬性,同時放開的playsinline的權限,好像在去年年末以前還須要向微信申請白名單才能夠,如今已經不須要了。playsinline可讓視頻內嵌在h5頁面中播放,這樣會讓用戶感受這個視頻就是h5的一部分,使用體驗上會好不少。我使用的video代碼以下:

<video class="video" id="video" x-webkit-airplay="allow" playsinline webkit-playsinline preload="auto" src="./video/rocket.mp4"></video>

在開始測試的時候發現,雖然視頻能夠內嵌播放了,可是在視頻上會出現一個全屏和一個小窗的按鈕。點擊全屏按鈕,視頻會全屏播放,播放完還會顯示廣告。。。點擊小窗按鈕,視頻會縮小成小窗。這兩個按鈕對於報告來講,就是多此一舉了。後面瞭解到這兩個按鈕是能夠隱藏的,可是須要向瀏覽器x5內核那邊申請白名單。申請後白名單後,按鈕就不會出現了

andriod的機器不支持autoplay,必定須要有交互(touch,click等)來能播放,因此在第一頁的時候當用戶touchstart的時候,調用下video.play();video.pause().同時,iphone不支持preload,在第一頁調用了video.play(),會觸發視頻的下載,在最後須要播放的時候,視頻能夠順利的播放。

視頻初始化在各個手機上表現的形式並不同,可是又須要有一個表現一致的效果。解決辦法是,在尚未進入到最後一頁的時候,設置video的寬高都爲1px,等進入到最後一頁的時候,在把寬度設爲100%,高度設爲auto。同時把視頻的第一幀設爲最後一頁的背景圖,這樣每一個人看到的第一眼畫面都是同樣的。這裏須要注意一點,在設置背景圖的時候background-size應該設置爲cover,否則在播放視頻的時候,若是視頻的寬高比跟手機寬高比不同會致使第一幀跳動的感受,體驗上會打折扣。

在視頻播放完後,會有文字再顯示出來。 開始的作法是監聽videoend 事件,可是這在iphone 上會出現屏幕黑一下,再出現文字。體驗上又會打折扣了。問題引發的緣由,應該是視頻播放完了,播放器的變成了黑色,就像在pc上播放完,播放器黑掉同樣。解決的辦法是: 設置一個定時器監聽video的currentTime,當currentTime距離視頻播放的時候還差幾百毫秒的時候,顯示文字,隱藏視頻。大概的代碼以下:

var videoTimer = setInterval(function () {
        if(video[0].currentTime > 6.5){
            if(!videoEnd){
                $(".check").show();
                $(".pub").show();
                $(".p2").css({'opacity': 1});
                $(".check").addClass('check-ani');
                $(".pub").addClass('check-ani');
                $(".dong").addClass('bounceInDown');
                $(".wish").addClass('wish-ani');
                videoEnd = 1;
            }
        }
    }, 200);

不過這須要在製做視頻的時候把這一段的時間留出來,同時也要考慮視頻結束時跟文字出來之間的銜接,這能夠跟設計師討論研究了。

難題: 在iphone上偶爾會出現,視頻不會播放。可是若是刷新下頁面視頻就能夠正常的播放了。 在用測試機來重現這種狀況的時候,又沒有遇到,很差定位到具體是啥緣由。 如今只有一個猜想的緣由:由於 video的play()方法即便是調用了,可是也不必定保證會播放。猜想多是視頻沒有緩衝好,在調用play() 方法後,視頻並無播放成功。 後面也是採起了定時去調用video的play()方法來嘗試解決這個問題,如今熱度也過了,也沒有收到視頻沒有播放的反饋。若是各位客官有碰到視頻沒有播放的狀況,麻煩留言通知聲。 在監聽視頻有沒有播放,是經過video 的timeupdate的事件來判斷,timeupdate事件在iOS和Android上表現一致。具體的代碼以下:

var videoPlayed = false;
video.on("timeupdate", function () {
        videoPlayed = true;
    });

// 到第九頁時判斷
if(pageIndex === 9){
  videoPlayed = false;
  videoPlayedTimer = setInterval(function () {
  if(!videoPlayed){
             playVideo();
             }
  }, 300);
 playVideo();
}

 

補充:
8.使用視頻的時候,開始設計師導出的視頻有1M多,這在移動端感受仍是有點太大了,何況視頻只有7s。 後來使用了ffmpeg來壓縮一下,視頻大小減小了不少。從最終的1.8M 減小到了330kb。同時在各個手機上的視頻清晰度變化肉眼是很難發現的。
我使用的是ffmpeg默認的轉換參數,固然你們也能夠根據須要本身調整。
ffmpeg -i r.mp4 r1.mp4

目前能想到的點,就這些了。你們若是看到有什麼地方錯了,也請指出來,共同窗習 ^_^。

 

文章轉載自:http://www.jianshu.com/p/40a41bdbe054

相關文章
相關標籤/搜索