首頁

有趣的Canvas,你值得擁有!

seo達(dá)人

Canvas 是 HTML5 提供的一個用于展示繪圖效果的標(biāo)簽. Canvas 原意為畫布, 在 HTML 頁面中用于展示繪圖效果. 最早 Canvas 是蘋果提出的一個方案, 今天已經(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)簽, 即可在頁面中開辟一格區(qū)域,可以設(shè)置其寬高,寬高為 300 和 150


<canvas></canvas>

2、獲取 dom 元素 canvas


canvas 本身不能繪圖. 是使用 JavaScript 來完成繪圖. canvas 對象提供了各種繪圖用的 api。


var cas = document.querySelector('canvas')

3、通過 cas 獲取上下文對象(畫布對象!)


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

4、通過 ctx 開始畫畫(設(shè)置起點(diǎn) 設(shè)置終點(diǎn) 連線-描邊 )


ctx.moveTo(10, 10)

ctx.lineTo(100, 100)

ctx.stroke()

繪制線條

設(shè)置開始位置: 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 繪制線段偏移量.

封裝一個畫矩形的方法


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) 繪制一個空心以(x,y)為起點(diǎn)寬高分別為 width、height 的矩形

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

繪制圓弧

繪制圓弧的方法有


CanvasRenderingContext2D.arc()

CanvasRenderingContext2D.arcTo()

6 個參數(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))


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

ctx.closePath()

ctx.stroke()


function degToArc(num) {

return (Math.PI / 180) * num

}

制作畫筆

聲明一個變量作為標(biāo)識

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

鼠標(biāo)移動的時候,開始描繪并連線

鼠標(biāo)抬起的時候,關(guān)閉開關(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)移動事件

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

if (!isDraw) {

// 沒有按下

return

}

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

var x = e.offsetX

var y = e.offsetY

ctx.lineTo(x, y)

ctx.stroke()

})


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

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

isDraw = false

})

手動涂擦

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


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


var cas = document.querySelector('canvas')

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


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


// 開關(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

})

刮刮樂

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

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

當(dā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')

// 加一個遮罩層

ctx.fillStyle = '#ccc'

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

setImgUrl()

// 開關(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,請查看 github.com/Michael-lzg…


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

前端達(dá)人

簡單來說,v-if 的初始化較快,但切換代價高;v-show 初始化慢,但切換成本低

1.共同點(diǎn)

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

2.區(qū)別

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



新版vue-router的hooks用法

seo達(dá)人

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


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


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




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


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


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


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

假如你在路由里面定義了一個動態(tài)參數(shù)通常都會這么寫:


{

   path: '/:id'

}

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


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

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


this.$route.params.id

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

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


import { defineComponent, getCurrentInstance } from 'vue'


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

   const { ctx } = getCurrentInstance()

   

   console.log(ctx.$route)

})

沒想到打印出來的居然是undefined!

這是咋回事呢?

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




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


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




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


import { defineComponent, getCurrentInstance } from 'vue'


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

   const { ctx } = getCurrentInstance()

   

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

})

果然獲取到了!好開心!


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

在接下來的過程中我用ctx.&dollar;router代替了原來的this.&dollar;router、用ctx.&dollar;router.currentRoute.value代替了原先的this.&dollar;route。


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


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


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


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




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


vue-router里的hooks

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


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


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


import { useXxx } from 'vue-router'

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


為了驗(yàn)證我的想法,我打開了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)路由,也同樣可以獲取到路由傳過來的參數(shù),這次再打包試了一下,果然就沒有之前的那個報錯了。


結(jié)語

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


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


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

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

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

資深UI設(shè)計者

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

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

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

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

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

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

開始前的準(zhǔn)備

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

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

2. 確定分析的目的

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

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

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

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

4. 其他tips

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

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

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

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

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

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

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

2. 如何去使用競品

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

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

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

3. 記錄

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

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

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

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

4. 各個擊破-功能了解

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

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

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

整體總結(jié)

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

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

文章來源:優(yōu)設(shè)    作者:箴鹽設(shè)計

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

資深UI設(shè)計者

1、

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

資深UI設(shè)計者

互聯(lián)網(wǎng)時代的人們早就受夠了信息爆炸,我們每天都會經(jīng)系統(tǒng)推送、應(yīng)用通知、微信、電話、短信等各類渠道收到大量消息。有多久你沒有查收自己的郵箱?就算打開郵件,又有多少推薦內(nèi)容讓你有興趣進(jìn)一步了解?是 EDM 老了沒用了?真正的原因,可能是我們一開始就錯誤地忽視了 EDM 設(shè)計。

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

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

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

避免成為垃圾郵件

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

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

保持最佳郵件格式

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

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

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

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

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

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

兼顧質(zhì)量和效率

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

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

文章來源:優(yōu)設(shè)    作者:魚子醬聊設(shè)計

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

資深UI設(shè)計者

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

滴滴出行-xpanel

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

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

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

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

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

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

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

抖音-TopView

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

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

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

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

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

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

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

淘寶-二樓

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

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

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

△ 不知道這個banner為什么要排擠我

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

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

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

豆瓣-疊加上滑板

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

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

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

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

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

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

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

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

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

seo達(dá)人

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

支持讀寫 Excel 的 node.js 模塊

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

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

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

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

代碼庫地址

https://github.com/lingxiaoyi/excel

安裝

npm install


npm install -g nodemon


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


使用

nodemon app.js


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

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

因?yàn)槊看紊赏瓯砀?,每次都需要打開表格查看樣式,在 windows 電腦中,打開表格之后就鎖定不能生成新文件了,本來想著能導(dǎo)出一個 html 文件對應(yīng)表格的樣式


node 調(diào)試

vscode 中打開調(diào)試右側(cè)設(shè)置編輯,將下方代碼復(fù)制進(jìn)去,點(diǎn) nodemon 啟動就可以進(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 目錄的作用

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


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

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


使用方法

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


npm run dev


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


小技巧

谷歌瀏覽器插件:


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

劃詞翻譯 用來翻譯一些看不懂的英文文檔

browser 目錄

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


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


npm run dev


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


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


一些概念

在使用這個庫之前,先介紹庫中的一些概念。


workbook 對象,指的是整份 Excel 文檔。我們在使用 js-xlsx 讀取 Excel 文檔之后就會獲得 workbook 對象。

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

cell 對象,指的就是 worksheet 中的單元格,一個單元格就是一個 cell 對象。

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

constXLSX = require('xlsx');

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

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


exceljs 使用注意

讀取文件問題

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


(async function (params) {

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

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

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

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

});

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

寬度設(shè)置

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

快捷查看列寬的方法,打開 wps 表格,長按列與列字母間的豎線,就能看到列寬,取厘米的單位即可.見下圖




前景色

前景色設(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 }, }


排版不一致的問題

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

問題詳細(xì)說明地址


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


參考資料

exceljs

node-xlsx

js-xlsx

日歷

鏈接

個人資料

存檔