首頁(yè)

有趣的Canvas,你值得擁有!

seo達(dá)人

Canvas 是 HTML5 提供的一個(gè)用于展示繪圖效果的標(biāo)簽. Canvas 原意為畫(huà)布, 在 HTML 頁(yè)面中用于展示繪圖效果. 最早 Canvas 是蘋(píng)果提出的一個(gè)方案, 今天已經(jīng)在大多數(shù)瀏覽器中實(shí)現(xiàn)。


canvas 的使用領(lǐng)域


游戲

大數(shù)據(jù)可視化數(shù)據(jù)

banner 廣告

多媒體

模擬仿真

遠(yuǎn)程操作

圖形編輯

判斷瀏覽器是否支持 canvas 標(biāo)簽


var canvas = document.getElementById('canvas')

if (canvas.getContext) {

console.log('你的瀏覽器支持Canvas!')

} else {

console.log('你的瀏覽器不支持Canvas!')

}

canvas 的基本用法

1、使用 canvas 標(biāo)簽, 即可在頁(yè)面中開(kāi)辟一格區(qū)域,可以設(shè)置其寬高,寬高為 300 和 150


<canvas></canvas>

2、獲取 dom 元素 canvas


canvas 本身不能繪圖. 是使用 JavaScript 來(lái)完成繪圖. canvas 對(duì)象提供了各種繪圖用的 api。


var cas = document.querySelector('canvas')

3、通過(guò) cas 獲取上下文對(duì)象(畫(huà)布對(duì)象!)


var ctx = cas.getContext('2d')

4、通過(guò) ctx 開(kāi)始畫(huà)畫(huà)(設(shè)置起點(diǎn) 設(shè)置終點(diǎn) 連線-描邊 )


ctx.moveTo(10, 10)

ctx.lineTo(100, 100)

ctx.stroke()

繪制線條

設(shè)置開(kāi)始位置: context.moveTo( x, y )

設(shè)置終點(diǎn)位置: context.lineTo( x, y )

描邊繪制: context.stroke()

填充繪制: context.fill()

閉合路徑: context.closePath()

canvas 還可以設(shè)置線條的相關(guān)屬性,如下:


CanvasRenderingContext2D.lineWidth 設(shè)置線寬.

CanvasRenderingContext2D.strokeStyle 設(shè)置線條顏色.

CanvasRenderingContext2D.lineCap 設(shè)置線末端類型,'butt'( 默認(rèn) ), 'round', 'square'.

CanvasRenderingContext2D.lineJoin 設(shè)置相交線的拐點(diǎn), 'miter'(默認(rèn)),'round', 'bevel',

CanvasRenderingContext2D.getLineDash() 獲得線段樣式數(shù)組.

CanvasRenderingContext2D.setLineDash() 設(shè)置線段樣式.

CanvasRenderingContext2D.lineDashOffset 繪制線段偏移量.

封裝一個(gè)畫(huà)矩形的方法


function myRect(ctxTmp, x, y, w, h) {

ctxTmp.moveTo(x, y)

ctxTmp.lineTo(x + w, y)

ctxTmp.lineTo(x + w, y + h)

ctxTmp.lineTo(x, y + h)

ctxTmp.lineTo(x, y)

ctxTmp.stroke()

}


var cas = document.querySelector('canvas')

var ctx = cas.getContext('2d')

myRect(ctx, 50, 50, 200, 200)

繪制矩形

fillRect( x , y , width , height) 填充以(x,y)為起點(diǎn)寬高分別為 width、height 的矩形 默認(rèn)為黑色

stokeRect( x , y , width , height) 繪制一個(gè)空心以(x,y)為起點(diǎn)寬高分別為 width、height 的矩形

clearRect( x, y , width , height ) 清除以(x,y)為起點(diǎn)寬高分別為 width、height 的矩形 為透明

繪制圓弧

繪制圓弧的方法有


CanvasRenderingContext2D.arc()

CanvasRenderingContext2D.arcTo()

6 個(gè)參數(shù): x,y(圓心的坐標(biāo)),半徑,起始的弧度(不是角度 deg),結(jié)束的弧度,(bool 設(shè)置方向 ! )


var cas = document.querySelector('canvas')

var ctx = cas.getContext('2d')


ctx.arc(100, 100, 100, 0, degToArc(360))

ctx.stroke()


// 角度轉(zhuǎn)弧度

function degToArc(num) {

return (Math.PI / 180) * num

}

繪制扇形


var cas = document.querySelector('canvas')

var ctx = cas.getContext('2d')


ctx.arc(300, 300, 200, degToArc(125), degToArc(300))


// 自動(dòng)連回原點(diǎn)

ctx.closePath()

ctx.stroke()


function degToArc(num) {

return (Math.PI / 180) * num

}

制作畫(huà)筆

聲明一個(gè)變量作為標(biāo)識(shí)

鼠標(biāo)按下的時(shí)候,記錄起點(diǎn)位置

鼠標(biāo)移動(dòng)的時(shí)候,開(kāi)始描繪并連線

鼠標(biāo)抬起的時(shí)候,關(guān)閉開(kāi)關(guān)

點(diǎn)擊查看效果圖


var cas = document.querySelector('canvas')

var ctx = cas.getContext('2d')


var isDraw = false

// 鼠標(biāo)按下事件

cas.addEventListener('mousedown', function () {

isDraw = true

ctx.beginPath()

})


// 鼠標(biāo)移動(dòng)事件

cas.addEventListener('mousemove', function (e) {

if (!isDraw) {

// 沒(méi)有按下

return

}

// 獲取相對(duì)于容器內(nèi)的坐標(biāo)

var x = e.offsetX

var y = e.offsetY

ctx.lineTo(x, y)

ctx.stroke()

})


cas.addEventListener('mouseup', function () {

// 關(guān)閉開(kāi)關(guān)了!

isDraw = false

})

手動(dòng)涂擦

原理和畫(huà)布相似,只不過(guò)用的是clearRect()方法。


點(diǎn)擊查看效果圖


var cas = document.querySelector('canvas')

var ctx = cas.getContext('2d')


ctx.fillRect(0, 0, 600, 600)


// 開(kāi)關(guān)

var isClear = false


cas.addEventListener('mousedown', function () {

isClear = true

})


cas.addEventListener('mousemove', function (e) {

if (!isClear) {

return

}

var x = e.offsetX

var y = e.offsetY

var w = 20

var h = 20

ctx.clearRect(x, y, w, h)

})


cas.addEventListener('mouseup', function () {

isClear = false

})

刮刮樂(lè)

首先需要設(shè)置獎(jiǎng)品和畫(huà)布,將畫(huà)布置于圖片上方蓋住,

隨機(jī)設(shè)置生成獎(jiǎng)品。

當(dāng)手觸摸移動(dòng)的時(shí)候,可以擦除部分畫(huà)布,露出獎(jiǎng)品區(qū)。

點(diǎn)擊查看效果圖


<div>

<img src="./images/2.jpg" alt="" />

<canvas width="600" height="600"></canvas>

</div>

css


img {

width: 600px;

height: 600px;

position: absolute;

top: 10%;

left: 30%;

}


canvas {

width: 600px;

height: 600px;

position: absolute;

top: 10%;

left: 30%;

border: 1px solid #000;

}

js


var cas = document.querySelector('canvas')

var ctx = cas.getContext('2d')

var img = document.querySelector('img')

// 加一個(gè)遮罩層

ctx.fillStyle = '#ccc'

ctx.fillRect(0, 0, cas.width, cas.height)

setImgUrl()

// 開(kāi)關(guān)

var isClear = false

cas.addEventListener('mousedown', function () {

isClear = true

})

cas.addEventListener('mousemove', function (e) {

if (!isClear) {

return

}

var x = e.offsetX

var y = e.offsetY

ctx.clearRect(x, y, 30, 30)

})

cas.addEventListener('mouseup', function () {

isClear = false

})


function setImgUrl() {

var arr = ['./images/1.jpg', './images/2.jpg', './images/3.jpg', './images/4.jpg']

// 0-3

var random = Math.round(Math.random() * 3)

img.src = arr[random]

}

更多demo,請(qǐng)查看 github.com/Michael-lzg…


v-if 和 v-show的區(qū)別

前端達(dá)人

簡(jiǎn)單來(lái)說(shuō),v-if 的初始化較快,但切換代價(jià)高;v-show 初始化慢,但切換成本低

1.共同點(diǎn)

都是動(dòng)態(tài)顯示DOM元素

2.區(qū)別

(1)手段:
v-if是動(dòng)態(tài)的向DOM樹(shù)內(nèi)添加或者刪除DOM元素;
v-show是通過(guò)設(shè)置DOM元素的display樣式屬性控制顯隱;
(2)編譯過(guò)程:
v-if切換有一個(gè)局部編譯/卸載的過(guò)程,切換過(guò)程中合適地銷毀和重建內(nèi)部的事件監(jiān)聽(tīng)和子組件;
v-show只是簡(jiǎn)單的基于css切換;
(3)編譯條件:
v-if是惰性的,如果初始條件為假,則什么也不做;只有在條件第一次變?yōu)檎鏁r(shí)才開(kāi)始局部編譯(編譯被緩存?編譯被緩存后,然后再切換的時(shí)候進(jìn)行局部卸載);
v-show是在任何條件下(首次條件是否為真)都被編譯,然后被緩存,而且DOM元素保留;
(4)性能消耗:
v-if有更高的切換消耗;
v-show有更高的初始渲染消耗;
(5)使用場(chǎng)景:
v-if適合運(yùn)營(yíng)條件不大可能改變;
v-show適合頻繁切換。



新版vue-router的hooks用法

seo達(dá)人

雖然Vue 3還沒(méi)有正式發(fā)布,但是熱愛(ài)新技術(shù)的我早已按捺不住自己的內(nèi)心,開(kāi)始嘗試在小項(xiàng)目中使用它了。


根據(jù)這篇《今日凌晨Vue3 beta版震撼發(fā)布,竟然公開(kāi)支持腳手架項(xiàng)目!》我搭建了一個(gè)Vue 3的腳手架項(xiàng)目,用這種方式搭建的腳手架項(xiàng)目不僅僅只有vue是新版的,就連vue-router、vuex都是的。


給大家截一下package.json的圖:




可以看到vue-router和vuex都已經(jīng)開(kāi)啟4.0時(shí)代啦!


不過(guò)其實(shí)我并沒(méi)有去了解過(guò)vue-router 4.0的新用法什么的,因?yàn)槲矣X(jué)得它不像vue 3.0都已經(jīng)進(jìn)行到beta的版本不會(huì)有特別大的變動(dòng)。


而vue-router 4.0還是alpha的階段,所以我認(rèn)為現(xiàn)在去學(xué)習(xí)它有些為時(shí)尚早。但卻就是它!差點(diǎn)釀成了一場(chǎng)慘劇。


舊版vue + vue-router的使用方式

假如你在路由里面定義了一個(gè)動(dòng)態(tài)參數(shù)通常都會(huì)這么寫(xiě):


{

   path: '/:id'

}

然后用編程式導(dǎo)航的時(shí)候通常會(huì)這樣去寫(xiě):


this.$router.push('/123')

在組件中是這樣獲取這個(gè)參數(shù)的:


this.$route.params.id

我以為的新版vue + vue-router的使用方式

由于vue 3.0的Composition API中沒(méi)有this了,所以我想到了通過(guò)獲取組件實(shí)例的方式來(lái)獲取$route:


import { defineComponent, getCurrentInstance } from 'vue'


export default defineComponent((props, context) => {

   const { ctx } = getCurrentInstance()

   

   console.log(ctx.$route)

})

沒(méi)想到打印出來(lái)的居然是undefined!

這是咋回事呢?

于是我又打印了一遍ctx(ctx是當(dāng)前組件上下文):




沒(méi)有&dollar;的那些字段是我在組件中自己定義的變量,帶&dollar;的這些就是vue內(nèi)置的了,找了半天發(fā)現(xiàn)沒(méi)有&dollar;route了,只剩下了一個(gè)&dollar;router,估計(jì)vue-router 4.0把當(dāng)前路由信息都轉(zhuǎn)移到$router里面去了。


帶著猜想,我點(diǎn)開(kāi)了&dollar;router:




currentRoute! 看名字的話感覺(jué)應(yīng)該就是它了!于是乎我:


import { defineComponent, getCurrentInstance } from 'vue'


export default defineComponent((props, context) => {

   const { ctx } = getCurrentInstance()

   

   console.log(ctx.$router.currentRoute.value.params.id)

})

果然獲取到了!好開(kāi)心!


實(shí)際的新版vue + vue-router用法

在接下來(lái)的過(guò)程中我用ctx.&dollar;router代替了原來(lái)的this.&dollar;router、用ctx.&dollar;router.currentRoute.value代替了原先的this.&dollar;route。


盡管在接下來(lái)的進(jìn)度中并沒(méi)有出現(xiàn)任何的bug,程序一直都是按照我所設(shè)想的那樣去運(yùn)行的。


但在項(xiàng)目打包后卻出現(xiàn)了意想不到的bug:在跳轉(zhuǎn)路由的時(shí)候報(bào)了一個(gè)在undefined上面沒(méi)有push的錯(cuò)誤。


奇了怪了,在開(kāi)發(fā)階段程序都沒(méi)有任何的報(bào)錯(cuò)怎么一打包就不行了呢?根據(jù)我多年的開(kāi)發(fā)經(jīng)驗(yàn),我很快就定位到了是vue-router的錯(cuò)誤。


難道這樣寫(xiě)是錯(cuò)的嗎?可是我打印了ctx,它里面明明有一個(gè)&dollar;router、&dollar;router里面明明就有currentRoute、currentRoute里面明明就有一個(gè)value、value里面明明就有params、params里面我一點(diǎn)開(kāi)明明就看到了傳過(guò)來(lái)的參數(shù)啊:




估計(jì)可能是vue-router的bug,果然alpha階段的產(chǎn)物不靠譜,我開(kāi)始后悔使用新版的vue腳手架項(xiàng)目了。


vue-router里的hooks

不過(guò)這時(shí)我突然靈光一現(xiàn),vue 3不是受到了react hooks的啟發(fā)才產(chǎn)生了Composition API的嗎?


那么估計(jì)vue-router肯定也會(huì)受到react-router的啟發(fā)了!


還好我學(xué)過(guò)react,果然技多不壓身??!估計(jì)里面肯定是有一個(gè)useXxx,就像這樣:


import { useXxx } from 'vue-router'

那么應(yīng)該是use什么呢?按理來(lái)說(shuō)應(yīng)該會(huì)盡量的和以前的API保持一定的聯(lián)系,我猜應(yīng)該是useRoute和useRouter吧!


為了驗(yàn)證我的想法,我打開(kāi)了node_modules找到了vue-router的源碼:




果不其然,在第2454和第2455行我發(fā)現(xiàn)它導(dǎo)出了useRoute和useRouter,那么就是它了:


import { defineComponent } from 'vue'

import { useRoute, useRouter } from 'vue-router'


export default defineComponent(_ => {

   const route = useRoute()

   const router = useRouter()


   console.log(route.params.id)

   router.push('/xxx/xxx')

})

使用這種方式不但可以成功跳轉(zhuǎn)路由,也同樣可以獲取到路由傳過(guò)來(lái)的參數(shù),這次再打包試了一下,果然就沒(méi)有之前的那個(gè)報(bào)錯(cuò)了。


結(jié)語(yǔ)

估計(jì)以后的vue全家桶要開(kāi)啟全民hooks的時(shí)代了,在翻看源碼的同時(shí)我發(fā)現(xiàn)他們把一些示例都寫(xiě)在了vue-router/playground文件夾下了,在里面我發(fā)現(xiàn)了一些有趣的用法。


如果有時(shí)間的話我會(huì)仔細(xì)研究一下然后出一篇更加深入的文章給大家,當(dāng)然如果已經(jīng)有小伙伴等不及我出新文章的話可以直接進(jìn)入vue-router-next的github地址:


https://github.com/vuejs/vue-router-next

它的示例都放在了playground這個(gè)文件夾下,期待你們研究明白后出一篇更加深入的文章!

B 端設(shè)計(jì)師如何做競(jìng)品分析?

資深UI設(shè)計(jì)者

將要分析的競(jìng)品排了個(gè)期,從最難最不熟悉的開(kāi)始。為什么從最難的開(kāi)始,可能是個(gè)人習(xí)慣吧,吃掉最難的那個(gè),后面就會(huì)更上手。突然想起之前讀的一本書(shū)「吃掉那只青蛙」,很不錯(cuò)的一本書(shū),有時(shí)間去溫習(xí)下。

一個(gè)產(chǎn)品,其實(shí)會(huì)有很多功能點(diǎn),有核心的主要功能,也有一些輔助功能,也會(huì)有一些讓你忽略,但關(guān)鍵時(shí)刻很需要的應(yīng)急功能,而這些點(diǎn)都需要去整理出來(lái)。

分析前-熟悉產(chǎn)品

這一點(diǎn)很重要,要先熟悉產(chǎn)品。如果對(duì)產(chǎn)品都不熟悉,那還是先不要做競(jìng)品分析。因?yàn)楹茈y判斷競(jìng)品的功能和風(fēng)格是否也適合當(dāng)前產(chǎn)品,因?yàn)閷?duì)產(chǎn)品的不熟悉,會(huì)產(chǎn)生誤判。

當(dāng)然,產(chǎn)品的目標(biāo)人群,產(chǎn)品定位,適用范圍等等,都會(huì)影響產(chǎn)品分析。

所以,花時(shí)間熟悉自己負(fù)責(zé)的產(chǎn)品,是不能跳過(guò)的。

開(kāi)始前的準(zhǔn)備

1. 制定時(shí)間規(guī)劃

最好事先做好時(shí)間規(guī)劃,可以有一整塊的時(shí)間,這樣分析產(chǎn)品時(shí),思緒也會(huì)比較完整和連續(xù),可以更專注。計(jì)算大概分析一個(gè)產(chǎn)品需要花費(fèi)的時(shí)間,最好不要用零碎時(shí)間來(lái)做,這樣只會(huì)增加時(shí)間上的代價(jià),也會(huì)增加挫折感;

2. 確定分析的目的

在「競(jìng)品分析」中,想要得到的結(jié)論和重點(diǎn)是什么。比如重點(diǎn)可能是產(chǎn)品的報(bào)表功能、產(chǎn)品的代碼審核功能等等,目的的確定能讓分析更有針對(duì)性,減少干擾。無(wú)目的隨意分析,得到的結(jié)果也會(huì)是零亂不堪,最后只是在浪費(fèi)時(shí)間。

3. 尋找?guī)椭?/strong>

每個(gè)產(chǎn)品,都有其不一樣的特性和產(chǎn)品邏輯,你不一定能夠完全 cover 到,甚至有些點(diǎn)就是比較難理解的,特別是偏技術(shù)性的名詞,這時(shí)若有技術(shù)同學(xué)的幫助,就會(huì)如虎添翼。所以最好可以事先找一位產(chǎn)品相關(guān)的技術(shù)同學(xué),詢問(wèn)這段時(shí)間是否有空,幫助你解答一些問(wèn)題。

個(gè)人建議:能夠在網(wǎng)上查到的資料,就不要先問(wèn)人,除非時(shí)間成本特別高。一方面也是提升自己解決問(wèn)題的能力,另一方面,也是節(jié)省彼此的時(shí)間。對(duì)方愿意幫你解決問(wèn)題,不代表你要把所有問(wèn)題一股腦倒給他,自己了解后再問(wèn),也是對(duì)對(duì)方的尊重,大家的時(shí)間都同樣寶貴。

4. 其他tips

如果是內(nèi)部公司產(chǎn)品,提前確認(rèn)是否需要權(quán)限,提前申請(qǐng)好,減少正式開(kāi)始后,還要等待審批時(shí)間。外部產(chǎn)品可以提前找好網(wǎng)站,可以咨詢的客服入口,如果是付費(fèi)競(jìng)品,咨詢是否可以向財(cái)務(wù)申請(qǐng)報(bào)銷等等。

好,現(xiàn)在正式開(kāi)始吧!

1. 像個(gè)用戶一樣去使用產(chǎn)品

很多時(shí)候,設(shè)計(jì)師的職業(yè)病,會(huì)讓我們過(guò)多注重視覺(jué)享受,而忽略作為用戶,想要的有時(shí)候只是功能可用。今天不管你把「掃一掃」功能做得多美,美得像個(gè)藝術(shù)品一樣,可是當(dāng)掃碼付款的時(shí)候,怎么也掃不出來(lái),那種站在店家前面忐忑不安,怎么也無(wú)法完成付款,后面一堆人等你,你仿佛聽(tīng)見(jiàn)后面其他顧客竊竊私語(yǔ)地討論著發(fā)生什么事情。那種場(chǎng)景我相信你不想經(jīng)歷,同樣我們也不應(yīng)該讓用戶來(lái)經(jīng)歷。

我的項(xiàng)目主管,一直都有提醒我,要像個(gè)小白來(lái)使用和設(shè)計(jì)我們的產(chǎn)品。這句建議,也一直在提醒著我。如果站在高姿態(tài)來(lái)俯視用戶,我們就很難真正的「懂」用戶,進(jìn)而很難設(shè)計(jì)出真正滿足用戶需要的產(chǎn)品。

這是競(jìng)品分析,但是我們也需要轉(zhuǎn)換自己的角色,變成用戶。這樣能更明白究竟競(jìng)品帶給用戶是便利,還是麻煩。有時(shí)適時(shí)抽離「設(shè)計(jì)師」的角色,會(huì)讓你更能去體會(huì)用戶的感受。

所以,先去用這個(gè)產(chǎn)品吧,然后才會(huì)有然后。

2. 如何去使用競(jìng)品

一個(gè)產(chǎn)品的使用,總是有它的使用場(chǎng)景,手機(jī)端的就更多樣了,簡(jiǎn)直無(wú)所不在。B 端產(chǎn)品可能會(huì)相對(duì)少,一般是在辦公場(chǎng)景或是特定場(chǎng)景。

可以像個(gè)編劇一樣,給自己寫(xiě)點(diǎn)劇本,加點(diǎn)情節(jié),塑造一個(gè)角色,假設(shè)競(jìng)品是電商方向,你可以想像,自己是一個(gè)剛畢業(yè)的社會(huì)新人,你可能沒(méi)多少錢(qián),你可能剛拿到你人生第一桶金,你想買(mǎi)件衣服犒勞自己,或許你會(huì)是數(shù)碼控,你關(guān)注已久的佳能單反在雙 11 中有優(yōu)惠等等,然后再去預(yù)想接下去的情節(jié),在購(gòu)物方面會(huì)考慮的問(wèn)題,或許是好用,或許是有趣等等。

也可以做任務(wù)式去使用產(chǎn)品,比如以電商為例,任務(wù)可以是買(mǎi)件喜歡的衣服,從搜索產(chǎn)品,到找到喜歡的衣服,添加購(gòu)物車,提交訂單,等待發(fā)貨,收貨,確認(rèn)收貨。這一個(gè)完整的流程走下來(lái),就會(huì)體驗(yàn)產(chǎn)品功能是否好用,搜索結(jié)果是否符合預(yù)期等等。

3. 記錄

使用產(chǎn)品的過(guò)程中,會(huì)遇到很多情況,有些是可預(yù)期的,有些是不可預(yù)期的。有些讓人覺(jué)得很好用,有些卻會(huì)讓人受挫。將這些情況都記錄下來(lái),有助于分析產(chǎn)品的可用性程度和滿意度。

  • 愉快的:可能是一個(gè)友好的提示,減輕你的認(rèn)知負(fù)擔(dān),也可以是一個(gè)貼心小 loading 動(dòng)畫(huà)等等
  • 受挫的:點(diǎn)擊沒(méi)有反饋,提交后沒(méi)反饋,不知道執(zhí)行成功與否等等
  • 難以理解:產(chǎn)品中專業(yè)名詞太多,沒(méi)有附帶解釋和幫助文檔,完全不知其所以然
  • 產(chǎn)生誤解:以為是 A,結(jié)果是 B
  • 一臉懵:頁(yè)面太亂,不知從哪里下手

上面這些只是舉例說(shuō)明,在競(jìng)品當(dāng)中可能遇到的一些問(wèn)題,也可以去反思自己的產(chǎn)品是否也會(huì)這樣讓用戶感到困惑。有時(shí)候,太熟悉自己的產(chǎn)品,會(huì)自認(rèn)為產(chǎn)品很完美,會(huì)理所當(dāng)然認(rèn)為「大家都這么認(rèn)為」……

記錄問(wèn)題、原因,感受并截圖為證(有必要可錄屏),后期可追溯。寫(xiě)得越詳細(xì)越好,后面整理的時(shí)候會(huì)更清晰。

4. 各個(gè)擊破-功能了解

在熟悉整個(gè)產(chǎn)品后,就需要對(duì)產(chǎn)品的各個(gè)功能進(jìn)行分析了解、梳理。了解競(jìng)品的核心功能是什么,核心功能在解決用戶什么問(wèn)題,是否真的解決了用戶的痛點(diǎn),其他功能又在整個(gè)產(chǎn)品當(dāng)中充當(dāng)什么樣的角色。

將競(jìng)品的功能與本產(chǎn)品功能對(duì)比,不只是對(duì)比有無(wú),更進(jìn)一步地去想,為什么有這個(gè)功能,為什么沒(méi)有這個(gè)功能,有或沒(méi)有是否會(huì)提高用戶的使用效率,用戶的留存,用戶的體驗(yàn)等等。

功能多不代表好,如果功能不能給用戶帶來(lái)益處,其實(shí)它的存在只是增加開(kāi)發(fā)成本而已。

整體總結(jié)

其實(shí)競(jìng)品分析中,最難的是總結(jié)歸納。做了一堆的分析后,結(jié)論是什么呢,這個(gè)結(jié)論如何寫(xiě)呢?

可以先從設(shè)立分析目的開(kāi)始,找到中心軸線,然后再慢慢延展開(kāi)來(lái)。在要做總結(jié)報(bào)告時(shí),你會(huì)欣喜地發(fā)現(xiàn)最初設(shè)立目標(biāo)是多么的重要。

文章來(lái)源:優(yōu)設(shè)    作者:箴鹽設(shè)計(jì)

這10個(gè)設(shè)計(jì)原則,是確保金融類產(chǎn)品體驗(yàn)優(yōu)秀的核心要義

資深UI設(shè)計(jì)者

1、

如何讓郵件體驗(yàn)設(shè)計(jì)更加吸引人?

資深UI設(shè)計(jì)者

互聯(lián)網(wǎng)時(shí)代的人們?cè)缇褪軌蛄诵畔⒈ǎ覀兠刻於紩?huì)經(jīng)系統(tǒng)推送、應(yīng)用通知、微信、電話、短信等各類渠道收到大量消息。有多久你沒(méi)有查收自己的郵箱?就算打開(kāi)郵件,又有多少推薦內(nèi)容讓你有興趣進(jìn)一步了解?是 EDM 老了沒(méi)用了?真正的原因,可能是我們一開(kāi)始就錯(cuò)誤地忽視了 EDM 設(shè)計(jì)。

對(duì)于 95 后以及更年輕的群體來(lái)說(shuō),EDM 確實(shí)是個(gè)上了年紀(jì)的概念。EDM(Email Direct Marketing)也叫 Email 營(yíng)銷、電子郵件營(yíng)銷。企業(yè)向目標(biāo)客戶發(fā)送 EDM 郵件,建立同目標(biāo)客戶的溝通渠道,向其直接傳達(dá)相關(guān)信息,用來(lái)促進(jìn)銷售轉(zhuǎn)化。

這個(gè)起源于上世紀(jì) 80 年代中期,正式誕生于 90 年代的早期互聯(lián)網(wǎng)產(chǎn)物現(xiàn)在已經(jīng)三十多歲了。時(shí)至今日,EDM 早已成為了全球公認(rèn)的網(wǎng)絡(luò)營(yíng)銷重要方法之一,其卓越效果為互聯(lián)網(wǎng)人數(shù)十年的實(shí)踐所證實(shí)。但 EDM 在我國(guó)的應(yīng)用還處于非常低級(jí)的水平,不僅沒(méi)有系統(tǒng)的理論,在實(shí)踐中也存在許多誤區(qū)。

在這樣一個(gè)重視審美與強(qiáng)調(diào)更新及時(shí)的時(shí)代,EDM 郵件樸實(shí)無(wú)華的外表與「一旦發(fā)出就固定呈現(xiàn)」的內(nèi)容特質(zhì)顯得有些格格不入。作為用戶體驗(yàn)設(shè)計(jì)師,我們可以做什么讓 EDM 不落伍呢?

避免成為垃圾郵件

首先,我們可以在設(shè)計(jì)層面上避免 EDM 郵件被郵箱軟件識(shí)別為垃圾郵件,不帶敏感詞語(yǔ)或內(nèi)容、淡化商業(yè)廣告色彩、減少數(shù)字與附件使用都有助于降低被郵箱系統(tǒng)屏蔽的風(fēng)險(xiǎn)。我們更可以在全量發(fā)送前,對(duì)指定郵箱進(jìn)行小范圍測(cè)試以確保郵件發(fā)送成功率。

其次,從其歷史來(lái)源來(lái)看,早期的 EDM 來(lái)源于垃圾郵件,這使人們對(duì)其本能地缺乏好感,存在排斥心理。因此 EDM 的節(jié)奏和時(shí)機(jī)必須做好控制,對(duì)郵件發(fā)送的各類數(shù)據(jù)做好統(tǒng)計(jì),掌握用戶的閱讀習(xí)慣,能更好地提升郵件的打開(kāi)率。

保持最佳郵件格式

郵件內(nèi)容需要設(shè)計(jì)為一定的格式來(lái)發(fā)送,常用的郵件格式包括純文本格式、HTML 格式和 Rich Media 格式,或者是這些格式的組合。一般來(lái)說(shuō),HTML 格式和 Rich Media 格式的電子郵件比純文本格式具有更好的體驗(yàn)效果。但 Rich Media 格式的電子郵件易造成郵件過(guò)大,并且無(wú)法確保用戶在客戶端均能夠正常顯示,所以在設(shè)計(jì)時(shí)我們優(yōu)先選擇 HTML 格式郵件。

確??缍梭w驗(yàn)

與網(wǎng)頁(yè)不同,我們無(wú)法針對(duì)不同設(shè)備做郵件內(nèi)容相應(yīng)的適配設(shè)計(jì),兼顧設(shè)備特性的通用模版也就成為了設(shè)計(jì)時(shí)的必要關(guān)注點(diǎn)。對(duì)用戶來(lái)說(shuō),一封郵件閱讀體驗(yàn)很差,那么無(wú)論郵件的內(nèi)容多么精彩、多么吸引人,最終的結(jié)果也可能只會(huì)被丟棄在一邊。因此,我們通常會(huì)按照移動(dòng)端尺寸對(duì)郵件界面進(jìn)行設(shè)計(jì),注意字體大小、最佳尺寸以及鏈接按鈕的大小等。

除此以外,郵件中鏈接的定義也應(yīng)得到我們充分的重視。由于郵件中的鏈接我們同樣無(wú)法預(yù)先針對(duì)不同打開(kāi)設(shè)備進(jìn)行單獨(dú)編輯,在有條件的情況下我們可以對(duì)鏈接所跳轉(zhuǎn)的頁(yè)面進(jìn)行響應(yīng)式設(shè)計(jì)以確保高質(zhì)量的跨端瀏覽體驗(yàn),或者我們也可以采用默認(rèn)跳轉(zhuǎn)路徑而后重定向的傳統(tǒng)方式。

與「我」緊密相關(guān)

EDM 營(yíng)銷與一般的營(yíng)銷方式最大的區(qū)別是:EDM 是一對(duì)一的溝通,讓用戶感覺(jué)到尊重,讓他感覺(jué)到這是為他所建立并且是他所獨(dú)享的溝通方式。在標(biāo)題、正文的文案上強(qiáng)調(diào)「我」,在內(nèi)容上也應(yīng)如此。用戶在意什么,我們就發(fā)送什么。把握住用戶關(guān)注的信息,幫助用戶收集支持 TA 做決策所需的信息。當(dāng)我們發(fā)送郵件給用戶,給予其操作行為的反饋或提醒時(shí),不要浪費(fèi)這最好的營(yíng)銷機(jī)會(huì)。優(yōu)先提供給用戶與之行為或特征相關(guān)的服務(wù)與幫助,其次通過(guò)個(gè)性化服務(wù)或產(chǎn)品推薦促進(jìn)購(gòu)買(mǎi)或注冊(cè)轉(zhuǎn)化,有助于我們將營(yíng)銷機(jī)會(huì)轉(zhuǎn)化為實(shí)際銷售成果。

兼顧質(zhì)量和效率

做好個(gè)性化對(duì) EDM 內(nèi)容模型要求頗高,但從設(shè)計(jì)角度講,我們完全可以以原子設(shè)計(jì)思維實(shí)現(xiàn)郵件內(nèi)容模塊的低成本創(chuàng)建與復(fù)用。以通用設(shè)計(jì)模塊為「殼」,內(nèi)容與組合規(guī)則為「核」,快速響應(yīng) EDM 的運(yùn)營(yíng)需求。

以上 5 點(diǎn)就是我結(jié)合近期項(xiàng)目經(jīng)驗(yàn)所得。EDM 雖老,但設(shè)計(jì)可以讓 EDM 老而彌新。祝經(jīng)你精心設(shè)計(jì)的 EDM 郵件,一經(jīng)發(fā)出,封封有回應(yīng)

文章來(lái)源:優(yōu)設(shè)    作者:魚(yú)子醬聊設(shè)計(jì)

用4個(gè)經(jīng)典的重量級(jí)產(chǎn)品案例,告訴你什么是標(biāo)桿式體驗(yàn)設(shè)計(jì)

資深UI設(shè)計(jì)者

今天和大家聊一個(gè)很多朋友常年卡在 P5/P6 需要關(guān)心的命題——如何從業(yè)務(wù)出發(fā)打造具有商業(yè)價(jià)值還能兼顧用戶體驗(yàn)的設(shè)計(jì),此篇不談理論,就通過(guò) 4 個(gè)經(jīng)典的重量級(jí)產(chǎn)品案例就給大家安排明白啥是「一拳超人」式體驗(yàn)設(shè)計(jì)——就一個(gè)字「強(qiáng)」。

滴滴出行-xpanel

滴滴出行應(yīng)該屬于大家的高頻使用 app,但是使用的功能一般還是集中在叫車流程,所以大家可能不太會(huì)關(guān)注到 CDX 設(shè)計(jì)團(tuán)隊(duì)一個(gè)非常核心的設(shè)計(jì)成果——xpanel。

簡(jiǎn)單來(lái)說(shuō) xpanel 就是一個(gè)附著于第一信息架構(gòu)層級(jí)上,垂直 Y 軸且支持 X 軸拓展滑動(dòng)的 Feed 卡片位。內(nèi)容上分為「消息卡片」「主體卡片」「拓展卡片」三個(gè)維度,首屏保障除了「消息」與「主體」外三分之一「拓展卡片1」的露出。

但在簡(jiǎn)單的交互背后蘊(yùn)藏的是基于業(yè)務(wù)的 UGD(用戶增長(zhǎng)設(shè)計(jì))設(shè)計(jì)思考,這里引用 2018IXDC 會(huì)上滴滴主講人的原話來(lái)說(shuō)就是:

對(duì)特定場(chǎng)景垂直領(lǐng)域的深耕和挖掘,尋找「接觸點(diǎn)」,幫助獲取更多的功能、內(nèi)容、服務(wù)、特性、品牌、運(yùn)營(yíng)甚至是喜好……進(jìn)而實(shí)現(xiàn)業(yè)務(wù)的「有效增長(zhǎng)」(轉(zhuǎn)化、變現(xiàn)、留存)。

通俗一點(diǎn)解釋就是 xpanel 利用主卡與拓展卡之間的信息架構(gòu)關(guān)系,把拓展卡平衡的分為幾類,比如「與產(chǎn)品功能相關(guān)的卡片」「與運(yùn)營(yíng)相關(guān)的卡片」等。

把本來(lái)被 LBS 地圖一屏內(nèi)搶占的空間通過(guò)簡(jiǎn)易的交互模式補(bǔ)償回來(lái)了,這樣既不打破用戶的核心體驗(yàn) focus 在地圖與主卡上,同時(shí)又增強(qiáng)了運(yùn)營(yíng)、功能的玩法與拓展,可謂雙贏。

根據(jù)這幾年滴滴 xpanel 的線上應(yīng)用,拓展卡片基本挖掘涵蓋了以下場(chǎng)景的露出:優(yōu)惠福利、出現(xiàn)卡券、會(huì)員體系、安全相關(guān)、出行提醒、拉新導(dǎo)流、運(yùn)營(yíng)活動(dòng)等,未來(lái)可拓展的價(jià)值內(nèi)容會(huì)更多??粗髀烦鲂蓄?app 又紛紛長(zhǎng)期沿用 xpanel 的設(shè)計(jì),想必線上的數(shù)據(jù)反饋應(yīng)該也是很正向的。

抖音-TopView

在上篇文章《多維度解析 | 抖音vs快手的產(chǎn)品設(shè)計(jì)策略差異》中的商業(yè)化模塊里簡(jiǎn)要提及過(guò)抖音的 Topiew 超級(jí)廣告位,這里單獨(dú)拿出來(lái)和大家解析一下它究竟有多6。

從功能角度看,它是一個(gè)從開(kāi)屏延續(xù)到端內(nèi)視頻信息流的廣告位,占據(jù)了用戶從進(jìn)入抖音的第一視覺(jué)。

從交互角度看,topview 主要展現(xiàn)以開(kāi)屏沉浸式視頻 3s 播放→淡出互動(dòng)轉(zhuǎn)化組件 3s(完美融入原生視頻信息流),剩余操作手勢(shì)與功能等同原生視頻信息流。

在這樣一個(gè)有著 1 億+第一曝光的產(chǎn)品位置,單純只做常規(guī)靜態(tài)開(kāi)屏穩(wěn)當(dāng)入賬不香嗎?事實(shí)是抖音確實(shí)讓它不香了,沒(méi)有創(chuàng)新就沒(méi)有新的收獲?;跇I(yè)務(wù)和當(dāng)前產(chǎn)品形態(tài)下的交互模式使抖音有一個(gè)天時(shí)地利的優(yōu)勢(shì)——沉浸式體驗(yàn),在這樣的交互模式下給視頻化的開(kāi)屏提供了很好的承接入口。從開(kāi)屏開(kāi)啟到融入信息流,在交互形態(tài)的切換中又為廣告內(nèi)容的播放時(shí)長(zhǎng)贏得了更多時(shí)間。

更可怕的一點(diǎn)是 3s 播放后融入原生視頻信息流中的 TopView 除了正常收割廣告轉(zhuǎn)化帶來(lái)的單量,還可以通過(guò)右側(cè)的主頁(yè)鏈接輕松引流進(jìn)行粉絲沉淀(今天就算你不買(mǎi),先關(guān)注我,成為我的潛在用戶,來(lái)日我再推一個(gè)新商品視頻,你可以第一時(shí)間看見(jiàn)也許感興趣就買(mǎi)單了)。

說(shuō)完這些大家仔細(xì)回憶一下平常我們接觸的有視頻廣告的視頻平臺(tái),別說(shuō) 60s、30s,15s 我們都嫌長(zhǎng),但為啥 TopView 顯得相對(duì)沒(méi)那么惹人煩呢(上次留的思考題)?個(gè)人認(rèn)為除了抖音在選擇合作品牌時(shí)會(huì)傾向符合平臺(tái)氣質(zhì)的品牌合作(細(xì)數(shù)它合作過(guò)的品牌:Mac、寶馬、林肯、vivo 等)保障廣告質(zhì)量和提供「跳過(guò)」外,直接融入信息淡出的互動(dòng)組件會(huì)不僅會(huì)給用戶新奇感,還會(huì)激發(fā)用戶的互動(dòng)欲望。

最后看一組數(shù)據(jù)(與寶馬合作數(shù)據(jù)),曝光數(shù):1.1 億+;有效播放率:53.82%;點(diǎn)擊率:13.26%。所以你猜一個(gè)最長(zhǎng)可以展示 60s 的品牌視頻內(nèi)容、同時(shí)進(jìn)行品牌粉絲沉淀、良好體驗(yàn)帶來(lái)更高有效播放的億級(jí)曝光廣告位能值多少錢(qián)?

淘寶-二樓

2016 年淘寶啟動(dòng)了一個(gè)項(xiàng)目要做一款內(nèi)容化欄目——以視頻為主,每晚更新一期,類比「一千零一夜」的故事。

那么在滿滿當(dāng)當(dāng)?shù)奶詫氝\(yùn)營(yíng)區(qū)里該選擇哪一個(gè)來(lái)試玩這個(gè)有趣的「新欄目」呢?是在頭部的 10 宮格里再擠進(jìn)去一個(gè)圖標(biāo)呢?還是在熱門(mén)推薦里擠出一個(gè) tab 呢?還是做一個(gè)懸浮的右下角的運(yùn)營(yíng)位?顯然都不太合適。

根據(jù)這款產(chǎn)品每晚 6 點(diǎn)鐘才可以使用,早上 7 點(diǎn)就會(huì)消失的游戲規(guī)則,最適配它的入口是一個(gè)不占界面原生空間,同時(shí)又有一定儀式感的位置。于是下拉 loading 的大空區(qū)成為了設(shè)計(jì)師們考慮的陣地。

△ 不知道這個(gè)banner為什么要排擠我

但地方選好了,又有了新顧慮。因?yàn)?iOS 的用戶基本被系統(tǒng)洗腦了下拉手勢(shì),對(duì)于他們來(lái)說(shuō)下拉=刷新,貿(mào)然在下拉刷新的手勢(shì)基礎(chǔ)上再疊加一個(gè)無(wú)關(guān)聯(lián)的結(jié)果顯然是有風(fēng)險(xiǎn)的。因此從交互上需要界定 2 個(gè)維度的指標(biāo)來(lái)保障新欄目的體驗(yàn)。

  • 下拉速度(速度臨界值:速度多快?→刷新,多慢?→新欄目)——以速度為優(yōu)先衡量指標(biāo)(只要速度快,拉的距離再大也是→刷新)
  • 下拉距離(距離臨界值:拉到多少距離進(jìn)入新欄目?)——兼顧單手用戶操作難度

反復(fù)試錯(cuò) 2 個(gè)指標(biāo)數(shù)據(jù)的實(shí)際體驗(yàn)之后,新欄目有了安身之所,賜名「二樓」。進(jìn)入「二樓」的整體交互和現(xiàn)在的短視頻產(chǎn)品玩法基本雷同,全屏豎滑切換,小圖標(biāo)帶貨。下拉加載位的開(kāi)發(fā),從普通 loading 動(dòng)效到運(yùn)營(yíng)位的植入基本被各類電商平臺(tái)輕松復(fù)刻了,因此這一切看上去更沒(méi)什么了得,但對(duì)于原創(chuàng)來(lái)說(shuō)那畢竟是 4 年前。

豆瓣-疊加上滑板

談到豆瓣我算是半個(gè)老用戶了,豆瓣自身是個(gè)比較復(fù)雜的集合多條業(yè)務(wù)線分支(「小組」「同城」「閱讀」「音影」……)的多生態(tài)產(chǎn)品,這里我們主要拿它 18 年 6.0 大改版中影音模塊的詳情頁(yè)大改造來(lái)說(shuō)事兒。

△ 可能有很多人已經(jīng)忘記6.0前的豆瓣電影詳情頁(yè)長(zhǎng)啥樣了,帶你回顧一下。

看完對(duì)比圖,視力正常的朋友乍一看都能看出 6.0 版詳情頁(yè)整容得有多成功。但具體成功在哪里,可能不僅僅是好看這么簡(jiǎn)單。

大背景從海報(bào)上智能取色雖然不算是什么稀奇的做法,但是加了適度的漸變應(yīng)用在這里也可以說(shuō)是非常的恰到好處了。另外深底色和視覺(jué)比重加大的外鏈區(qū)都突顯了「第三方播放」與「購(gòu)票選座」的視覺(jué)感知。讓用戶沉浸在電影詳情中并引導(dǎo)他們走向「豆瓣的主要收入來(lái)源之一——電影票分銷與第三方視頻播放產(chǎn)品引流」正好是 6.0 豆瓣改版一個(gè)「小小的目標(biāo)」——更務(wù)實(shí)(商業(yè)化)。

從交互層面看,且不說(shuō)評(píng)論頭部吸底這個(gè)事情是不是也是因?yàn)?6.0 商業(yè)化的影響(評(píng)論區(qū)增加「話題」進(jìn)行重點(diǎn)運(yùn)營(yíng)),這個(gè)交互本身我覺(jué)得還是很強(qiáng)大的。強(qiáng)大的體現(xiàn)在于良好的空間收納能力與信息拓展能力。我給它起了個(gè)好聽(tīng)的名字叫-疊加上滑板(不好聽(tīng)也認(rèn)了吧,畢竟也沒(méi)有內(nèi)部人員告訴我他們是不是起名字了)

這里可能又會(huì)有很多人質(zhì)疑它與用戶已洗腦的上滑手勢(shì)之間的沖突,這點(diǎn)解釋起來(lái)和上文淘寶「二樓」有些類似,區(qū)別是豆瓣并沒(méi)有做上滑速度 or 距離的臨界值,只是把滑動(dòng)區(qū)域做了隔離。而對(duì)比它的效仿者 boss 直聘,人家倒是在交互上做了進(jìn)一步優(yōu)化,適配自己的產(chǎn)品情況做了上滑疊層卡隱藏和上滑距離臨界值。

這個(gè)故事告訴我們,要抄也要抄得比人家的交互更優(yōu)秀才不丟人昂。

文章來(lái)源:優(yōu)設(shè)    作者:Nana的設(shè)計(jì)錦囊

前端實(shí)現(xiàn)生成帶有樣式的excel表格 Node和瀏覽器讀寫(xiě)Excel文件探究實(shí)踐

seo達(dá)人

最近碰到個(gè)需要自動(dòng)生成表格的任務(wù),作為前端的我,就想在 node 和瀏覽器中生成強(qiáng)大的表格,所以特此研究了很多關(guān)于表格的 npm 庫(kù)

支持讀寫(xiě) Excel 的 node.js 模塊

node-xlsx: 基于 Node.js 解析 excel 文件數(shù)據(jù)及生成 excel 文件,僅支持 xlsx 格式文件

js-xlsx: 目前 Github 上 star 數(shù)量最多的處理 Excel 的庫(kù),支持解析多種格式表格 XLSX / XLSM / XLSB / XLS / CSV,解析采用純 js 實(shí)現(xiàn),寫(xiě)入需要依賴 nodejs 或者 FileSaver.js 實(shí)現(xiàn)生成寫(xiě)入 Excel,可以生成子表 Excel,功能強(qiáng)大,但上手難度稍大。不提供基礎(chǔ)設(shè)置 Excel 表格 api 例單元格寬度,文檔有些亂,不適合快速上手;普通版本不支持定義字體、顏色、背景色等,有這個(gè)功能需要的可以使用 pro 版,是要聯(lián)系客服收費(fèi)的,害我照著 API 設(shè)置調(diào)試了好多次都失敗。好在樣式設(shè)置問(wèn)題有一些教程,通過(guò)研究本人已解決,可設(shè)置寬度顏色等等,見(jiàn)根目錄本人修改的 xlsx.js

xlsx-style 基于 xlsx 封裝的樣式庫(kù),可以在 xlsx 的基礎(chǔ)上設(shè)置樣式。樣式不全,寬度都設(shè)置不了,好多年前作者就不維護(hù)了.寬度設(shè)置問(wèn)題本人已解決了,見(jiàn)修改的 xlsx-style.js 文件

exceljs 在使用此庫(kù)之前,本人已花費(fèi)了很大的精力,用以上庫(kù)做好了表格,但是發(fā)現(xiàn)不能設(shè)置頁(yè)眉頁(yè)腳,添加圖片,打印選項(xiàng)設(shè)置等等,直到發(fā)現(xiàn)了這個(gè)庫(kù),文檔齊全,功能強(qiáng)大,并且還免費(fèi).但是star較少,差一點(diǎn)就錯(cuò)過(guò)了。本教程主要針對(duì)這個(gè)庫(kù)

代碼庫(kù)地址

https://github.com/lingxiaoyi/excel

安裝

npm install


npm install -g nodemon


調(diào)試使用,替代 node 命令,實(shí)現(xiàn)保存文件,node 自動(dòng)重新啟動(dòng)執(zhí)行,必須全局安裝才能運(yùn)行


使用

nodemon app.js


js-xlsx 具體 api 使用方法請(qǐng)參考 main.js demo 使用,app.js 中修改為 require('./src/main.js');

exceljs 具體 api 使用方法請(qǐng)參考 main-exceljs.js demo 使用,app.js 中修改為 require('./src/main-exceljs.js');

因?yàn)槊看紊赏瓯砀瘢看味夹枰蜷_(kāi)表格查看樣式,在 windows 電腦中,打開(kāi)表格之后就鎖定不能生成新文件了,本來(lái)想著能導(dǎo)出一個(gè) html 文件對(duì)應(yīng)表格的樣式


node 調(diào)試

vscode 中打開(kāi)調(diào)試右側(cè)設(shè)置編輯,將下方代碼復(fù)制進(jìn)去,點(diǎn) nodemon 啟動(dòng)就可以進(jìn)行 debug 調(diào)試了


{

     "type": "node",

     "request": "launch",

     "name": "nodemon",

     "runtimeExecutable": "nodemon",

     "program": "${workspaceFolder}/app.js",

     "restart": true,

     "console": "integratedTerminal",

     "internalConsoleOptions": "neverOpen",

     "skipFiles": ["<node_internals>/**"]

   },

webpack 目錄的作用

每次生成完新表格,都需要重新打開(kāi)表格查看樣式,在 windows 電腦中,打開(kāi)表格之后就鎖定了,再次生成新表格就會(huì)報(bào)錯(cuò),文件已鎖定,不能寫(xiě)入,對(duì)于想偷懶的我,能不能實(shí)現(xiàn)像 webpack 熱更新功能那種,修改樣式 js 頁(yè)面自動(dòng)更新呢?


wps 自帶另存 html 文件功能,但是沒(méi)有提供生成的 api ,網(wǎng)上也搜索不到對(duì)應(yīng)的轉(zhuǎn)換功能,

本來(lái)以為自己要實(shí)現(xiàn)一套表格轉(zhuǎn) html 的功能。通過(guò)不斷嘗試,偶然間發(fā)現(xiàn)手機(jī)瀏覽器可以直接打開(kāi)預(yù)覽 xlsx 文件,內(nèi)心狂喜啊


使用方法

進(jìn)入 webpack 目錄安裝依賴包,安裝好之后執(zhí)行


npm run dev


啟動(dòng)成功之后,會(huì)自動(dòng)打開(kāi)帶有 ip 地址的預(yù)覽地址,此時(shí)在電腦瀏覽器會(huì)自動(dòng)下載 xlsx 文件,忽略不管,用手機(jī)直接打開(kāi)此地址,就能看到 xlsx 表格的內(nèi)容了,并且每次新修改內(nèi)容和樣式,都會(huì)自動(dòng)刷新頁(yè)面顯示新表格.


小技巧

谷歌瀏覽器插件:


生成二維碼的插件生成二維碼方便手機(jī)掃描

劃詞翻譯 用來(lái)翻譯一些看不懂的英文文檔

browser 目錄

瀏覽器中實(shí)現(xiàn)生成 xlsx 表格方法


進(jìn)入 browser 目錄安裝依賴包,安裝好之后執(zhí)行


npm run dev


啟動(dòng)成功之后,拖動(dòng)根目錄 src 下的李四表格到頁(yè)面上的輸入框里,成功生成表格之后會(huì)生成一個(gè)下載鏈接地址,右鍵在新標(biāo)簽頁(yè)打開(kāi)鏈接,即會(huì)生成一個(gè)新的表格文件出來(lái),完整 api 使用和 demo 文件請(qǐng)參考 index.js


vue 和 react 用法可以參考此例子,如果有必要也可以此版本庫(kù)的例子


一些概念

在使用這個(gè)庫(kù)之前,先介紹庫(kù)中的一些概念。


workbook 對(duì)象,指的是整份 Excel 文檔。我們?cè)谑褂?js-xlsx 讀取 Excel 文檔之后就會(huì)獲得 workbook 對(duì)象。

worksheet 對(duì)象,指的是 Excel 文檔中的表。我們知道一份 Excel 文檔中可以包含很多張表,而每張表對(duì)應(yīng)的就是 worksheet 對(duì)象。

cell 對(duì)象,指的就是 worksheet 中的單元格,一個(gè)單元格就是一個(gè) cell 對(duì)象。

xlsx 使用注意事項(xiàng)

constXLSX = require('xlsx');

let html = XLSX.utils.sheet_to_html(workbook.Sheets.Sheet1)

生成 html 的用法,并且不會(huì)有任何樣式


exceljs 使用注意

讀取文件問(wèn)題

因?yàn)?exceljs 讀取文件不支持 sync 同步讀取,給的實(shí)例也是 await 例子.導(dǎo)致我讀取完遇到一個(gè)問(wèn)題,就是老是生成不成功,最后發(fā)現(xiàn)必須要把所有邏輯全部放入函數(shù)中,像下方這樣


(async function (params) {

 let res = await workbook.xlsx.readFile(`${__dirname}/趙六.xlsx`);

 //執(zhí)行所有數(shù)據(jù)處理邏輯

 //執(zhí)行寫(xiě)的邏輯

 workbook.xlsx.writeFile(path.resolve(__dirname, '../webpack/test222.xlsx'));

});

所有邏輯全部要寫(xiě)入這個(gè)函數(shù)中,這樣本來(lái)是可以的,但是出錯(cuò)調(diào)試幾率較大,并且讀取到的數(shù)據(jù)龐大還需要額外處理,所以我讀取數(shù)據(jù)邏輯就用的 node-xlsx,十分簡(jiǎn)單方便,如果你用的 exceljs 讀取文件數(shù)據(jù)出現(xiàn)問(wèn)題,大概率是異步同步邏輯搞錯(cuò)了,多加注意即可

寬度設(shè)置

列寬不知道是以什么為單位,反正不是像素(已測(cè)量),例子中是以厘米為單位再乘以 4.7 的結(jié)果設(shè)置的,4.7 是不斷測(cè)試的結(jié)果.

快捷查看列寬的方法,打開(kāi) wps 表格,長(zhǎng)按列與列字母間的豎線,就能看到列寬,取厘米的單位即可.見(jiàn)下圖




前景色

前景色設(shè)置必須右鍵單元格選擇設(shè)置單元格格式,然后選擇圖案樣式選擇顏色,就可以前景色填充

worksheet.getCell('A2').fill = { type: 'pattern', pattern:'darkTrellis', fgColor:{argb:'FFFFFF00'}, bgColor:{argb:'FF0000FF'} };


背景色

worksheet.getCell('A2').fill = { type: "pattern", pattern: "solid", fgColor: { argb: next.bgColor }, }


排版不一致的問(wèn)題

解決 Mac 下編輯 Microsoft Office Word 文檔與 Windows 排版不一致的問(wèn)題,,不同的系統(tǒng)用 wps 打開(kāi)相同的表格,打印預(yù)覽的時(shí)候,表格寬度顯示不一樣

問(wèn)題詳細(xì)說(shuō)明地址


我的解決辦法就是 mac 下顯示正常,按 mac 下的寬度來(lái)設(shè)置就可以了


參考資料

exceljs

node-xlsx

js-xlsx

日歷

鏈接

個(gè)人資料

存檔