首页

微信小程序总结跳转方式,解决跳转失效问题

seo达人

微信小程序跳转方式

1.navigator 跳转

最常见的跳转方法就是运用<navigator url="../../.."></navigator>进行跳转,只要在url中添加跳转页面的路径即可。



代码

<navigator url="../skill/skill">

    ........//跳转涵盖内部所有代码形成的页面

</navigator>

1

2

3

2.运用 bindtap在js中实现页面的跳转

比起navigator的跳转,个人更喜欢用bindtap跳转,运用更灵活,也不用去除点击样式。

bindtap='home'(home位置随便替换)



代码

//wxml

 <view  bindtap='home'>

 </view>



//js

home: function (e) {

     wx.navigateTo({

       url: '../../..'        //跳转链接

     })

   }



**重点

在开发的过程中,突然遇到以上两种方式都无法实现跳转,也不会报错的情况,经过查询资料,发现内部调用wx.switchTab可以很好的解决这一现象



代码

home: function (e) {

      wx.switchTab({

        url: '../../..'

      })

    }


Vuex源码分析

seo达人

一、前言

我们都知道,vue组件中通信是用props进行父子通信,或者用provide和inject注入的方法,后者类似与redux的porvider,父组件使用,包含在里面的子组件都可以使用,provide/inject用法看我的博客(provide/inject用法),provide/indect官方文档,不过provide/indect一般用的不多,都是用前者,但是props有一个问题,父传子没问题,但是子后面还有子,子后面还有子,子子孙孙无穷尽也,所以这就要一层层的传下去,太麻烦了,所以vuex就派上用场了,vuex作为一个很轻量的状态管理器,有着简单易用的的API接口,在任意组件里面都能使用,获取全局状态,统一获取改变,今天,就看一下源码怎么实现的。



二、准备

1)先去github上将vuex源码下载下来。

2)打开项目,找到examples目录,在终端,cd进入examples,执行npm i,安装完成之后,执行node server.js



3)执行上述之后,会得到下方的结果,表示编译完成,打开浏览器 输入 localhost:8080



4) 得到页面,点击counter



5)最终,我们就从这里出发调试吧。





三、调试

找到counter目录下的store.js 写一个debugger,浏览器打开F12,刷新页面,调试开始。



1.Vue.use()

先进入Vue.use(Vuex),这是Vue使用插件时的用法,官方文档也说了,Vue.use,会调用插件的install方法,所以如果你要写插件的话,你就要暴露一个install方法,详情请看vue官方文档之use的用法



即use会调用下方的方法(debugger会进入)



function initUse (Vue) {

  Vue.use = function (plugin) {

    var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));

    if (installedPlugins.indexOf(plugin) > -1) {

      return this

    }



    // additional parameters

    var args = toArray(arguments, 1);

    args.unshift(this);

    if (typeof plugin.install === 'function') { 

    // 如果插件的install是一个function,调用install,将 this指向插件,并将Vue作为第一个参数传入

    // 所以调用vuex吧this指向vuex,并吧vue当参数传入

      plugin.install.apply(plugin, args);

    } else if (typeof plugin === 'function') {

      plugin.apply(null, args);

    }

    installedPlugins.push(plugin);

    return this

  };

}





1.1 vuex的install方法

在源码目录的src目录下的store.js文件里最下方有个install函数,会调用它



debugger进入后



export function install (_Vue) { // _Vue是上面说的Vue作为第一个参数 ,指针this指向Vuex

  if (Vue && _Vue === Vue) {

   // 如果你在开发环节,你使用了两次Vue.use(Vuex) 就会报下方的错误,提醒你vue只能被use一次,可以自行试试

    if (process.env.NODE_ENV !== 'production') {

      console.error(

        '[vuex] already installed. Vue.use(Vuex) should be called only once.'

      )

    }

    return

  }

  Vue = _Vue

  applyMixin(Vue) // 调用applyMixin方法

}



1.2 vuex的applyMixin方法

applyMixin方法在mixin.js文件里 同样在src目录下



export default function (Vue) {

  const version = Number(Vue.version.split('.')[0]) // 获取vue的版本



  if (version >= 2) { // vue的版本是2.xx以上 执行vue的mixin混入,该函数不懂用法请查看官方文档,

  // mixin合并混入操作,将vuexInit 方法混入到beforeCreate生命周期,意思就是当执行beforeCreate周期的时候

  // 会执行vuexInit 方法

    Vue.mixin({ beforeCreate: vuexInit })

  } else { // 1.xxx版本太老了 现在基本不用,暂不讲解,可以自行了解

    // override init and inject vuex init procedure

    // for 1.x backwards compatibility.

    const _init = Vue.prototype._init

    Vue.prototype._init = function (options = {}) {

      options.init = options.init

        ? [vuexInit].concat(options.init)

        : vuexInit

      _init.call(this, options)

    }

  }



  /*

   
Vuex init hook, injected into each instances init hooks list.

   /



  function vuexInit () { 

  // 因为该方法是在beforeCreate下执行,而beforeCreate的this指向为Vue 所以this === Vue

  // 获得vue里面的option配置,这里涉及到vue的源码,以后再讲vue ,

  //所以这就是我们为什么要在new Vue的时候,传递一个store进去的原因,

  //因为只有传进去,才能在options中获取到store

  /


  var vm = new Vue({

el: "#app",

data() {return{}},

store

})

*/

    const options = this.$options

    // store injection

    if (options.store) { 

    // 如果options对象中store有,代表是root ,如果options.store是函数,执行调用options.store()

    // 如果是对象直接options.store 赋值给this.$stroe

  // 这也就是我们为什么能够在Vue项目中直接this.$store.disptach('xxx')的原因,从这里获取

      this.$store = typeof options.store === 'function'

        ? options.store()

        : options.store

    } else if (options.parent && options.parent.$store) { 

    // 如果options.store为空,则判断options.parent.$store有没有 从父元素判断有没有store,

    //从而保证子元素父元素公用一个store实例

      this.$store = options.parent.$store

    }

  }

}





1.3 Vue.use(Vuex)总结

至此,Vue.use(Vuex)全部分析完成,总结,就是Vue.use调用Vuex的install的方法,然后install使用mixin混入beforecreate生命周期中混入一个函数,当执行生命周期beforecreate的时候回执行vuexInit 。你可以慢慢调试,所以要好好利用下方的调试按钮,第二个按钮执行下一步,第三个进入方法,两个配合使用。





2.new Vuex.Store

Vue.use(Vuex)已经结束,再回到counter目录下的store.js文件



export default new Vuex.Store({

  state,

  getters,

  actions,

  mutations

})





debugger进入,Vuex.Store方法在src目录下的store.js文件下



export class Store {

  constructor (options = {}) {

  // 这里的options是在counter定义的 state,getters,actions,mutations当做参数传进来

    // Auto install if it is not done yet and window has Vue.

    // To allow users to avoid auto-installation in some cases,

    // this code should be placed here. See #731

    if (!Vue && typeof window !== 'undefined' && window.Vue) {

    // 挂载在window上的自动安装,也就是通过script标签引入时不需要手动调用Vue.use(Vuex)

      install(window.Vue)

    }



    if (process.env.NODE_ENV !== 'production') { 

     // 开发环境 断言,如果不符合条件 会警告,这里自行看

      assert(Vue, must call Vue.use(Vuex) before creating a store instance.)

      assert(typeof Promise !== 'undefined', vuex requires a Promise polyfill in this browser.)

      assert(this instanceof Store, store must be called with the new operator.)

    }



    const {

      plugins = [],

      strict = false

    } = options



    // store internal state

    //下方是在Vuex的this上挂载一些对象,这里暂且不要知道他们要来干什么

    // 因为是源码分析,不要所有的代码都清除,第一次源码分析,你就只当他们是挂载对象,往下看

    this._committing = false

    this._actions = Object.create(null)

    this._actionSubscribers = []

    this._mutations = Object.create(null)

    this._wrappedGetters = Object.create(null)

    // ModuleCollection代表模块收集,形成模块树

    this._modules = new ModuleCollection(options) //碰到第一个不是定义空对象,debugger进去,分析在下面

    this._modulesNamespaceMap = Object.create(null)

    this._subscribers = []

    this._watcherVM = new Vue()

    this._makeLocalGettersCache = Object.create(null)



    // bind commit and dispatch to self

    const store = this

    const { dispatch, commit } = this

    this.dispatch = function boundDispatch (type, payload) { // 绑定dispatch的指针为store

      return dispatch.call(store, type, payload)

    }

    this.commit = function boundCommit (type, payload, options) { // 绑定commit的指针为store

      return commit.call(store, type, payload, options)

    }



    // strict mode

    this.strict = strict



    const state = this._modules.root.state // 获取到用户定义的state



    // init root module.

    // this also recursively registers all sub-modules

    // and collects all module getters inside this._wrappedGetters

    // 初始化root模块 注册getters,actions,mutations 子模块

    installModule(this, state, [], this._modules.root)



    // initialize the store vm, which is responsible for the reactivity

    // (also registers _wrappedGetters as computed properties)

    // 初始化vm 用来监听state getter

    resetStoreVM(this, state)



    // apply plugins

    // 插件的注册

    plugins.forEach(plugin => plugin(this))

// 下方的是开发工具方面的 暂不提

    const useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools

    if (useDevtools) {

      devtoolPlugin(this)

    }

  }

  }



2.1 new ModuleCollection

ModuleCollection函数在src目录下的module目录下的module-collection.js文件下



export default class ModuleCollection {

  constructor (rawRootModule) { // rawRootModule === options

    // register root module (Vuex.Store options)

    this.register([], rawRootModule, false)

  }

}



2.1.1 register()



 register (path, rawModule, runtime = true) {

 // register([],options,false)

    if (process.env.NODE_ENV !== 'production') {

      assertRawModule(path, rawModule) // 开发环境断言,暂忽略

    }



    const newModule = new Module(rawModule, runtime)

    if (path.length === 0) { // path长度为0,为根节点,将newModule 赋值为root

      this.root = newModule

    } else {

      const parent = this.get(path.slice(0, -1))

      parent.addChild(path[path.length - 1], newModule)

    }



    // register nested modules

    if (rawModule.modules) { // 如果存在子模块,递归调用register,形成一棵树

      forEachValue(rawModule.modules, (rawChildModule, key) => {

        this.register(path.concat(key), rawChildModule, runtime)

      })

    }

  }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

2.1.2 new Module()

Module函数在同目录下的modele.js文件下



export default class Module {

// new Module(options,false)

  constructor (rawModule, runtime) {

    this.runtime = runtime

    // Store some children item

    this._children = Object.create(null)

    // Store the origin module object which passed by programmer

    this._rawModule = rawModule // 将options放到Module上 用_raModele上

    const rawState = rawModule.state // 将你定义的state取出



    // Store the origin module's state

    // 如果你定义的state为函数,调用函数,为对象,则取对象 赋值为module上的state上

    this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}

  }

}



所以Module的this内容为如下:



2.1.3 installModule



function installModule (store, rootState, path, module, hot) {

// installModule(Vuex,state,[],module) module是前面 new ModuleCollection产生的对象

  const isRoot = !path.length

  const namespace = store._modules.getNamespace(path)



  // register in namespace map

  if (module.namespaced) {

    if (store._modulesNamespaceMap[namespace] && process.env.NODE_ENV !== 'production') {

      console.error([vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')})

    }

    store._modulesNamespaceMap[namespace] = module

  }



  // set state

  if (!isRoot && !hot) {

    const parentState = getNestedState(rootState, path.slice(0, -1))

    const moduleName = path[path.length - 1]

    store._withCommit(() => {

      if (process.env.NODE_ENV !== 'production') {

        if (moduleName in parentState) {

          console.warn(

            [vuex] state field "${moduleName}" was overridden by a module with the same name at "${path.join('.')}"

          )

        }

      }

      Vue.set(parentState, moduleName, module.state)

    })

  }

// 设置当前上下文

  const local = module.context = makeLocalContext(store, namespace, path)

// 注册mutation

  module.forEachMutation((mutation, key) => {

    const namespacedType = namespace + key

    registerMutation(store, namespacedType, mutation, local)

  })

// 注册action

  module.forEachAction((action, key) => {

    const type = action.root ? key : namespace + key

    const handler = action.handler || action

    registerAction(store, type, handler, local)

  })

// 注册getter

  module.forEachGetter((getter, key) => {

    const namespacedType = namespace + key

    registerGetter(store, namespacedType, getter, local)

  })

// 逐一注册子module

  module.forEachChild((child, key) => {

    installModule(store, rootState, path.concat(key), child, hot)

  })

}



2.1.4 makeLocalContext



// 设置module的上下文,绑定对应的dispatch、commit、getters、state

function makeLocalContext (store, namespace, path) {

  const noNamespace = namespace === ''



  const local = {

   //noNamespace 为true 使用原先的 至于后面的 不知道干啥用的 后面继续研究

    dispatch: noNamespace ? store.dispatch : (_type, _payload, _options) => {

      const args = unifyObjectStyle(_type, _payload, _options)

      const { payload, options } = args

      let { type } = args



      if (!options || !options.root) {

        type = namespace + type

        if (process.env.NODE_ENV !== 'production' && !store._actions[type]) {

          console.error([vuex] unknown local action type: ${args.type}, global type: ${type})

          return

        }

      }



      return store.dispatch(type, payload)

    },



    commit: noNamespace ? store.commit : (_type, _payload, _options) => {

    //noNamespace 为true 使用原先的

      const args = unifyObjectStyle(_type, _payload, _options)

      const { payload, options } = args

      let { type } = args



      if (!options || !options.root) {

        type = namespace + type

        if (process.env.NODE_ENV !== 'production' && !store._mutations[type]) {

          console.error([vuex] unknown local mutation type: ${args.type}, global type: ${type})

          return

        }

      }



      store.commit(type, payload, options)

    }

  }



  // getters and state object must be gotten lazily

  // because they will be changed by vm update

  Object.defineProperties(local, {

    getters: {

      get: noNamespace

        ? () => store.getters

        : () => makeLocalGetters(store, namespace)

    },

    state: {

      get: () => getNestedState(store.state, path)

    }

  })



  return local

}



function getNestedState (state, path) {

  return path.reduce((state, key) => state[key], state)

}

2.1.5 registerMutation

mutation的注册,会调用下方方法,将wrappedMutationHandler函数放入到entry中



function registerMutation(store, type, handler, local) {

 // entry和store._mutations[type] 指向同一个地址

  var entry = store._mutations[type] || (store._mutations[type] = []);

  entry.push(function wrappedMutationHandler(payload) {

    handler.call(store, local.state, payload);

  });

}





2.1.6 forEachAction

action的注册,会调用下方方法,将wrappedActionHandler函数放入到entry中



function registerAction(store, type, handler, local) {

  var entry = store._actions[type] || (store._actions[type] = []);

   // entry和store._actions[type]指向同一个地址

  entry.push(function wrappedActionHandler(payload) {

    var res = handler.call(store, {

      dispatch: local.dispatch,

      commit: local.commit,

      getters: local.getters,

      state: local.state,

      rootGetters: store.getters,

      rootState: store.state

    }, payload);

    if (!(0, _util.isPromise)(res)) {

      res = Promise.resolve(res);

    }

    if (store._devtoolHook) {

      return res.catch(function (err) {

        store._devtoolHook.emit('vuex:error', err);

        throw err;

      });

    } else {

      return res;

    }

  });

}



因为entry和上面的_action[type],_mutations[type] 指向同一个地址,所以:



2.1.7 forEachGetter

getter的注册,会调用下方方法



function registerGetter(store, type, rawGetter, local) {

  if (store._wrappedGetters[type]) {

    if (true) {

      console.error('[vuex] duplicate getter key: ' + type);

    }

    return;

  }

  store._wrappedGetters[type] = function wrappedGetter(store) {

    return rawGetter(local.state, // local state

    local.getters, // local getters

    store.state, // root state

    store.getters // root getters

    );

  };

}







2.1.8 resetStoreVM



function resetStoreVM (store, state, hot) {

  const oldVm = store._vm //将_vm用变量保存



  // bind store public getters

  store.getters = {}

  // reset local getters cache

  store._makeLocalGettersCache = Object.create(null)

  const wrappedGetters = store._wrappedGetters // 获取installModule方法完成的_wrappedGetters内容

  const computed = {}

  forEachValue(wrappedGetters, (fn, key) => {

    // use computed to leverage its lazy-caching mechanism

    // direct inline function use will lead to closure preserving oldVm.

    // using partial to return function with only arguments preserved in closure environment.

    computed[key] = partial(fn, store)

    Object.defineProperty(store.getters, key, {

    // 拦截get返回store._vm[key]中的值,即可以通过 this.$store.getters.xxx访问值

      get: () => store._vm[key],

      enumerable: true // for local getters

    })

  })



  // use a Vue instance to store the state tree

  // suppress warnings just in case the user has added

  // some funky global mixins

  const silent = Vue.config.silent

  // silent设置为true,取消所有日志警告等

  Vue.config.silent = true

  store._vm = new Vue({ // 将state,getter的值进行监听,从这里就可以看出getter其实就是采用的vue的computed

    data: {

      $$state: state

    },

    computed

  })

  // 恢复原先配置

  Vue.config.silent = silent



  // enable strict mode for new vm

  if (store.strict) {

    enableStrictMode(store)

  }

// 若存在旧的实例,解除对state的引用,等dom更新后把旧的vue实例销毁

  if (oldVm) {

    if (hot) {

      // dispatch changes in all subscribed watchers

      // to force getter re-evaluation for hot reloading.

      store._withCommit(() => {

        oldVm._data.$$state = null

      })

    }

    Vue.nextTick(() => oldVm.$destroy())

  }

}



看到这里,你应该对vuex有初步的了解



 // 这也是我们为什么能用访问到state,getter的原因

 //this.store.dispatch('xxx') ,this.$store.dispatch('xxx')

1

2

相信你也有点乱,其实上面很多我没讲到的不是我不想讲,是具体我也不知道干啥的,看源码学习呢,看主要就行,后面理解多了,其他的就慢慢都会,你不可能刚开始看,就每一行,他写的每一句的用途都知道是干什么的,只能先看主要方法,在慢慢琢磨,一步步来吧,别急,现在我来画一个流程图,更好的去理解吧。

2.1.9 流程图





3.连贯

import Vue from 'vue'

import Counter from './Counter.vue'

import store from './store'



new Vue({

  el: '#app',

  store,

  render: h => h(Counter)

})



当运行new Vue的时候,传入了store,前面minix beforecreate,执行到beforecreate钩子时,会调用vueInit函数,就可以在this.$store取到store对象了,因为options.store有值了 ,不为空,这样就连贯到了,所以这就是为什么可以用this.$store取值。


HTML常用meta大全

seo达人

HTML常用meta大全

Meta标签是HTML语言head区的一个辅助性标签,它位于HTML文档头部的head标记和title标记之间,它提供用户不可见的信息。



Meta : 即 元数据(Metadata)是数据的数据信息。



元数据可以被使用浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 Web 服务调用。



用我们的大白话来说,它本身是一个没什么用的标签,但是一旦在它内部通过其他属性设置了某些效果,它就起作用了,所以我们称之为“ 元数据 ”。



Code

<!-- 定义文档的字符编码 -->

<meta charset="utf-8" /> 

<!-- 强制Chromium内核,作用于360浏览器、QQ浏览器等国产双核浏览器 -->

<meta name="renderer" content="webkit"/>

<!-- 强制Chromium内核,作用于其他双核浏览器 -->

<meta name="force-rendering" content="webkit"/>

<!-- 如果有安装 Google Chrome Frame 插件则强制为Chromium内核,否则强制本机支持的最高版本IE内核,作用于IE浏览器 -->

<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"/>

<!-- 

    设置视窗大小

    width 设置layout viewport  的宽度,为一个正整数,或字符串"width-device"

    initial-scale 设置页面的初始缩放值,为一个数字,可以带小数

    minimum-scale 允许用户的最小缩放值,为一个数字,可以带小数

    maximum-scale 允许用户的最大缩放值,为一个数字,可以带小数

shrink-to-fit=no IOS9中要想前面的属性起作用需要加上这个

    height 设置layout viewport  的高度,这个属性对我们并不重要,很少使用

    user-scalable 是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes代表允许

-->

<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>

<!-- 页面描述 -->

<meta name="description" content="不超过150个字符"/>

<!-- 页面关键词 -->

<meta name="keywords" content=""/>

<!-- 网页作者 -->

<meta name="author" content="name, email@gmail.com"/>

<!-- 

    搜索引擎抓取

    all:文件将被检索,且页面上的链接可以被查询; 

    none:文件将不被检索,且页面上的链接不可以被查询;

    index:文件将被检索; 

    follow:页面上的链接可以被查询; 

    noindex:文件将不被检索; 

    nofollow:页面上的链接不可以被查询。 

-->

<meta name="robots" content="index,follow"/>

<!-- 忽略页面中的数字识别为电话,忽略email识别-->

<meta name="format-detection" content="telphone=no, email=no"/>



<!-- IOS begin -->

<!-- 添加到主屏后的标题(iOS 6 新增) -->

<meta name="apple-mobile-web-app-title" content="标题">

<!-- 当网站添加到主屏幕快速启动方式,可隐藏地址栏,仅针对ios的safari (ios7.0版本以后,safari上已看不到效果) -->

<meta name="apple-mobile-web-app-capable" content="yes"/>

<!-- 是否启用 WebApp 全屏模式,删除苹果默认的工具栏和菜单栏 -->

<meta name="apple-touch-fullscreen" content="yes"/>

<!-- 添加智能 App 广告条 Smart App Banner(iOS 6+ Safari) -->

<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">

<!-- 设置苹果工具栏颜色:默认值为 default(白色),可以定为 black(黑色)和 black-translucent(灰色半透明) -->

<meta name="apple-mobile-web-app-status-bar-style" content="black"/>

<!-- 不让百度转码 -->

<meta http-equiv="Cache-Control" content="no-siteapp" />

<!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 -->

<meta name="HandheldFriendly" content="true">

<!-- 微软的老式浏览器 -->

<meta name="MobileOptimized" content="320">

<!-- uc强制竖屏 -->

<meta name="screen-orientation" content="portrait">

<!-- QQ强制竖屏 -->

<meta name="x5-orientation" content="portrait">

<!-- UC强制全屏 -->

<meta name="full-screen" content="yes">

<!-- QQ强制全屏 -->

<meta name="x5-fullscreen" content="true">

<!-- UC应用模式 -->

<meta name="browsermode" content="application">

<!-- QQ应用模式 -->

<meta name="x5-page-mode" content="app">

<!-- windows phone 点击无高光 -->

<meta name="msapplication-tap-highlight" content="no">



<!-- 

    iOS 图标 begin 

    网站添加至ios桌面时的图标

-->

<!-- iPhone 和 iTouch,默认 57x57 像素,必须有 -->

<link rel="apple-touch-icon-precomposed" sizes="57x57" href="table_ico57.png">

<!-- Retina iPhone 和 Retina iTouch,114x114 像素,可以没有,但推荐有 -->

<link rel="apple-touch-icon-precomposed" sizes="72x72" href="table_ico72.png">

<link rel="apple-touch-icon-precomposed" sizes="114x114" href="table_ico114.png">

<!-- Retina iPad,144x144 像素,可以没有,但推荐有 -->

<link rel="apple-touch-icon-precomposed" sizes="144x144" href="table_ico144.png">



<!-- iOS 启动画面 begin -->

<!-- iPad 竖屏 768 x 1004(标准分辨率) -->

<link rel="apple-touch-startup-image" sizes="768x1004" href="/splash-screen-768x1004.png"/>

<!-- iPad 横屏 1024x748(标准分辨率) -->

<link rel="apple-touch-startup-image" sizes="1024x748" href="/Default-Portrait-1024x748.png"/>

<!-- iPad 竖屏 1536x2008(Retina) -->

<link rel="apple-touch-startup-image" sizes="1536x2008" href="/splash-screen-1536x2008.png"/>

<!-- iPad 横屏 2048x1496(Retina) -->

<link rel="apple-touch-startup-image" sizes="2048x1496" href="/splash-screen-2048x1496.png"/>

<!-- iPhone/iPod Touch 竖屏 320x480 (标准分辨率) -->

<link rel="apple-touch-startup-image" href="/splash-screen-320x480.png"/>

<!-- iPhone/iPod Touch 竖屏 640x960 (Retina) -->

<link rel="apple-touch-startup-image" sizes="640x960" href="/splash-screen-640x960.png"/>

<!-- iPhone 5/iPod Touch 5 竖屏 640x1136 (Retina) -->

<link rel="apple-touch-startup-image" sizes="640x1136" href="/splash-screen-640x1136.png"/>

<!-- IOS end -->



<!-- Windows 8 磁贴颜色 -->

<meta name="msapplication-TileColor" content="#000"/>

<!-- Windows 8 磁贴图标 -->

<meta name="msapplication-TileImage" content="icon.png"/>

<!-- 添加 RSS 订阅 -->

<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml"/>



<!-- sns 社交标签 begin -->

<!-- 参考微博API -->

<meta property="og:type" content="类型" />

<meta property="og:url" content="URL地址" />

<meta property="og:title" content="标题" />

<meta property="og:image" content="图片" />

<meta property="og:description" content="描述" />

<!-- sns 社交标签 end -->



低版本IE浏览器访问问题

添加好强制Webkit内核的代码,使用国产浏览器访问网站已经不存在IE兼容问题了,IE访客量将大大减少。但仍然不可避免会有一些老旧电脑通过低版本IE浏览器访问,如果我们专门为了这极小部分用户进行 CSS HACK ,将严重加重我们的工作量。



更何况自2016年1月起微软已经停止为IE11以下版本提供支持和更新,已经这么久没有更新,低版本IE不仅对CSS3和HTML5支持有问题,更有安全问题。



那么,我们不去支持低版本IE,这小部分用户怎么办呢?



我们可以使用 if IE 语句给网站添加IE升级提示,提示用户进行浏览器升级,或者切换更先进的浏览器再访问。



我们可以在刚刚的meta标签下添加一段跳转到IE升级提示页的代码(当IE版本低于IE11时跳转),实现低版本IE用户访问时提示他们进行升级或者更换浏览器。



强制Webkit内核和提示低版本IE访问用户升级完整代码如下所示,把这段代码添加到头部模板文件标签下即可:



<meta name="renderer" content="webkit"/>

<meta name="force-rendering" content="webkit"/>

<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>

<script>/@cc_on window.location.href="http://support.dmeng.net/upgrade-your-browser.html?referrer="+encodeURIComponent(window.location.href); @/</script>

1

2

3

4

(@cc_on 是 IE10 及更旧版IE特有的条件编译语句,因此可以用来判断是否除 IE11 以外的其他IE版本。)



因为低版本IE访问时因为不兼容CSS3和HTML5网站往往是错版的,添加了上面这段代码,当低版本IE用户访问时就会跳转到升级提示页,避免不必要的资源加载,降低网站服务器开销。



测试代码

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

<meta name="renderer" content="webkit"/>

<meta name="force-rendering" content="webkit"/>

<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>

<script>/@cc_on window.location.href="http://support.dmeng.net/upgrade-your-browser.html?referrer="+encodeURIComponent(window.location.href); @/</script>

  </head>

  <body>

<h1>Hello world</h1>

  </body>

</html>



IE 11 会正常输出





IE 10 将会看到以下页面





参考



前端 Meta 用法大汇总 - MR_LIXP



通过meta代码强制浏览器使用WebKit内核极速模式(解决 meta name=“renderer” content=“webkit” 不起作用)- 艾欢欢




replace与replaceAll的区别

seo达人

概述



replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了也就是字符串)



replaceAll的参数是regex,即基于规则表达式的替换,比如:可以通过replaceAll("\d", “*”)把一个字符串所有的数字字符都换成星号



相同点



相同点:都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串



不同点



不同点:replaceAll支持正则表达式,因此会对参数进行解析(两个参数均是),如replaceAll("\d", “"),而replace则不会,replace("\d","”)就是替换"\d"的字符串,而不会解析为正则



另外还有一个不同点:“\”在java中是一个转义字符,所以需要用两个代表一个。例如System.out.println( “\” ) ;只打印出一个""。但是“\”也是正则表达式中的转义字符,需要用两个代表一个。所以:\被java转换成\,\又被正则表达式转换成\,因此用replaceAll替换“\”为"\",就要用replaceAll("\","\\"),而replace则replace("\","\")



如果只想替换第一次出现的,可以使用replaceFirst(),这个方法也是基于规则表达式的替换,但与replaceAll()不同的是,只替换第一次出现的字符串




HTTP响应状态代码----成功响应(200–299)

seo达人

HTTP响应状态码

200 OK

201 Created

202 Accepted

203 Non-Authoritative Information

204 No Content

205 Reset Content

206 Partial Content

207 Multi-Status (WebDAV)

226 IM Used (HTTP Delta encoding)

200 OK

请求成功。成功的含义取决于HTTP方法:



GET:资源已被提取并在消息正文中传输。

HEAD:实体标头位于消息正文中。

POST:描述动作结果的资源在消息体中传输。

TRACE:消息正文包含服务器收到的请求消息

PUT 和 DELETE 的请求成功通常并不是响应200 OK的状态码而是 204 No Content 表示无内容(或者 201 Created表示一个资源首次被创建成功)。



201 Created

表示请求已经被成功处理,并且创建了新的资源。

这通常是在POST请求,或是某些PUT请求之后返回的响应。

新的资源在应答返回之前已经被创建。同时新增的资源会在应答消息体中返回,其地址是原始请求的路径或者是 Location 首部的值。



202 Accepted

表示服务器端已经收到请求消息,但是尚未进行处理。

但是稍后无法通过 HTTP 协议给客户端发送一个异步请求来告知其请求的处理结果。该状态码适用于将请求交由另外一个进程或者服务器来进行处理,或者是对请求进行批处理的情形。



203 Non-Authoritative Information

表示服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。

当前的信息可能是原始版本的子集或者超集。例如,包含资源的元数据可能导致原始服务器知道元信息的超集。

使用此状态码不是必须的,而且只有在响应不使用此状态码便会返回200 OK的情况下才是合适的。



204 No Content

表示该请求已经成功了,但是客户端客户不需要离开当前页面。

默认情况下 204 响应是可缓存的。一个 ETag 标头包含在此类响应中。



使用惯例是:



在 PUT 请求中进行资源更新,但是不需要改变当前展示给用户的页面,那么返回 204 No Content。

如果创建了资源,则返回 201 Created 。

如果应将页面更改为新更新的页面,则应改用 200 。

205 Reset Content

用来通知客户端重置文档视图,比如清空表单内容、重置 canvas 状态或者刷新用户界面。



与204响应一样,该响应也被禁止包含任何消息体,且以消息头后的第一个空行结束。



206 Partial Content

服务器已经成功处理了部分 GET 请求。



类似于 FlashGet 或者迅雷这类的 HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。



该请求必须包含 Range 头信息来指示客户端希望得到的内容范围,并且可能包含 If-Range 来作为请求条件。



如果只包含一个数据区间,那么整个响应的 Content-Type 首部的值为所请求的文件的类型,同时包含 Content-Range 首部。



示例:



HTTP/1.1 206 Partial Content

Date: Wed, 15 Nov 2015 06:25:24 GMT

Last-Modified: Wed, 15 Nov 2015 04:58:08 GMT

Content-Range: bytes 21010-47021/47022

Content-Length: 26012

Content-Type: image/gif



... 26012 bytes of partial image data ...



包含多个数据区间,那么整个响应的Content-Type首部的值为multipart/byteranges,其中一个片段对应一个数据区间,并提供 Content-Range 和 Content-Type 描述信息。



示例:



HTTP/1.1 206 Partial Content

Date: Wed, 15 Nov 2015 06:25:24 GMT

Last-Modified: Wed, 15 Nov 2015 04:58:08 GMT

Content-Length: 1741

Content-Type: multipart/byteranges; boundary=String_separator



--String_separator

Content-Type: application/pdf

Content-Range: bytes 234-639/8000



...the first range...

--String_separator

Content-Type: application/pdf

Content-Range: bytes 4590-7999/8000



...the second range

--String_separator--



207 Multi-Status (WebDAV)

代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。由WebDAV(RFC 2518)扩展的状态码.



226 IM Used (HTTP Delta encoding)

服务器已经完成了对资源的 GET 请求,并且响应是对当前实例应用的一个或多个实例操作结果的表示。






移动端 Banner 设计指南

雪涛

根据遇到的问题,总结的一些小经验,个人的一点薄见,欢迎大家交流。

国内国外运营 Banner 设计

最近有小伙伴接到了国外的运营外包项目,发现国外和国内对于运营的需求是有差别的,这篇文章就谈谈国内外:中国、韩国、欧美,它们运营设计的各自特点和里面的门道。

主要从以下三方面来说:

1. 风格特点

三个地区文化差异大不相同。

中国从古到今讲究遵循传统,过年过节讲究气氛,营造一种氛围。用红包来表达祝福和心意;其次,就是社会环境,中国人喜欢「热闹」,逢年过节,一帮人聚到一起才热闹,别人都买、卖的火的肯定就是好的,所以就「跟风效仿」。

韩国建国很晚,历史相对比较短。所以文化氛围比较年轻,偶像文化在韩国盛行,传统的东西相对较少,都是比较年轻化的:年轻化的偶像,年轻化的文化,年轻化的价值观。

欧美整个文化环境受移民的影响,比较开放国际化,体现的文化也是比较多元的,包容性、简洁、时尚是这些它最直接的特点。

接下来分别谈一下三个地区运营推广的设计特点差异化:

中国

中国的运营突出的是优惠:送红包、满减、优惠券等;必须要喜庆,鲜艳的色彩:以红色、橙色、黄色居多,来刺激消费。就好像进了卖场「瞧一瞧看一看,季末打折满100减99」

韩国

韩国的文化里「社交」这一关键词体现的尤为重要,「Line」这款APP对韩国影响比较大,里面的矢量涂鸦风格的插画深入人心,Line 官方设计可爱且特色鲜明的「馒头人」、「可妮兔」、「布朗熊」和「詹姆士」四个形象也很有特点,所以Line的「IP属性」和「矢量涂鸦」就成为了韩国主流设计风格。

2. 整体构图

而韩国的偶像明星文化也颇具影响力,在推广时也会用到明星来制造效应。

我们从整体构图解析一下三个地区的设计细节。首先把一个运营 banner 按照组件层级进行拆分,分别来看一下。

分为:文字层、主体物层、装饰层、背景层

文字层

从文字层可以看出中国的文字层级划分更加清晰。运用「格式塔」原理,主文案和副标题的突出,能让用户对信息提取更加准确直观。

中文结构的复杂性,排版上必须严格区分,所以在层级划分上装饰线的运用也是比较常见的。(后面有针对性字体设计形式,详细解读,这里就不细说了)

韩文的本身的图形特质,为保证识别度,文案提炼精简,信息层级相对较少。文字层级一般分为两层。

有意思的是韩文由于字形结构的单一,排版上很多时候会搭配字体形式的变化来增加排版样式的变化,装饰线的运用也比较多变。

英文排版上本质上和韩文相同——符号化,通过字形的特点来特出主要信息。

排版的优势性,让其排版变化上自带韵律感,加上装饰线的运用,本身字形的符号特性视觉呈现很有设计感。

主体物层

为了辅助信息传达,往往采用图文结合,注意主体物的构图布局朝向,主题物对主要文字起到视觉引导作用,用户的聚焦点一定是主文案,而不是主体物。

下图里「手」作为整个画面的「支点」,把模特的脸部向主要文案指引,最终达到活动的最核心。

下图里「眼睛」为整个画面的「支点」,利用眼睛视线,把用户向文案核心指引。

利用周围的物体形成三个「支点」,把视觉中心聚焦到中间主文案。

装饰层

点线面是运用最多的元素,中国把平面设计的三大构成运用到了。

为了营造构图的稳定性,在设计里加入点和线的元素让画面占比更加平衡,同时弥补画面中空白的地方,减少负空间,让构图更加饱满。

同时点和线的元素也是为了辅助衬托主体元素,分布要合理,避免过多,造成使画面的拥挤。

面简单的理解成形状,用形状配合主体物,达到聚焦视觉中心,来突出主题,但是形状不易过于复杂,「格式塔原理」——「简单」原则(我们的眼睛在观看时,眼脑并不是在一开始就区分一个形象的各个单一的组成部分,而是将各个部分组合起来,使之成为一个更易于理解的统一体),用户更容易理解。

三角形——利用稳定的特点来达到视觉的平衡

圆形——最简单直接有效的图形元素,视觉聚焦更明确

多边形——丰富画面,多边形的边角多的特点也多用做突出设计的高逼格

形状流体在营销中突出了活动的促销感和气氛,在重大活动中经常看到,色彩上也比较鲜艳。相较欧美、韩国,中国电商运用比较多,这也侧面反映出出中国运营推广竞争的残酷性映射出来的「浮夸」。

背景层

中国设计里最多变的就属背景了。可以利用多彩渐变、放射的线、还有图案叠加,让画面迎合表达的主体基调

韩国的设计分为涂鸦放射背景和纯色背景简单几何形状

欧美撞色对比和性冷淡纯色底,也会运用视错觉,来吸引用户眼球

3. 营销推广层面

文案是营销第一要素,想办法突出运营信息,是所有运营必须要注意的,这就有了根据活动气氛进行字体设计。

中国字体的复杂和文化的久远特殊性,对于字体我们是有很深的研究和造诣,表现空间也很大。另外由于中文字形的复杂,导致字库设计成本比较大,字体种类相对较少,为了避免字体版权问题,多采用一些设计变形来达到营销推广目的。比如针对字形进行改变、针对笔画进行加工、针对体积和质感进行变化等。

层次叠加——提取等比重的笔画,变现字体的体积和空间感

笔画链接——让文字直接更紧凑,空间运用更整体合理

笔画装饰——增加文字设计感,突出表现风格

厚度层次——让字体突出,增加厚重感

字形改变设计——考虑到字体版权,对字体进行再设计,结合主题进行宣传

字体内部装饰——字体呼应主题的一种简单方式

韩国字形相对简单,变化不是很多,运用厚度体积和笔画装饰来表现字体

欧美的西文字体更多的是运用和主体物穿插、和字形搭配的变换,和复古风字体厚度设计

4. 小结

可以看到不同的国家地区根据本国习惯、审美、风格不同,都有各自不同的设计。中国营销快速简单直接出效果;韩国偶像路线,不管是对于模特的选择,还是网红形象的选择,把粉丝效应运用到了;而欧美则简单兼顾设计创意表现。

浅谈学习Banner

随着教育在大趋势下崛起,很多学习类产品开始出现。很多在做教育的小伙伴求助,学习类的运营 banner 无从下手,思路不清晰,那么我稍稍的屡了一下思路,浅谈一下学习 banner 的个人薄见。

在很多设计师刚开始缕思路的时候,总因为无从下手而着急盲目,下意识的认为「我不会啊」!那复杂的不会,就从简单的开始缕。从设计开始,我构图都没想好,设计啥设计?那再简单点,从构图开始吧,我思路都没想好,构啥图?继续再简单点,一步一步往前推,直到推到最简单的细节,从最初第一步开始做。你会发现,首先第一步就是先建立一个符合主题的思路。

谈到学习类 banner,光听一听就觉得头大甚至很讨厌的事情。因为本来学习就是让人很拒绝的,如何引导用户主动做一个不想做的事,就得用到一些特殊的手段了。

咱们这次主要从以下方面来多维度探讨:

1. 主题定位方向

K12教育

K12 也就是九年义务教育和三年高中,所以人群定位青少年,年龄 7-18 岁。这个年龄段非常单纯。

大家可以回想一下我们小时候,在这个年龄最享受的是什么?那就是「满足感」和「参与感」,我们小时候玩积木、做游戏,最重要的不是赢了能得到什么东西,而是参与到其中享受快乐。所以建立一种参与感,参与进来「一起玩」的感觉,就会得到满足。

我们看到下面这类 APP,为了能够吸引这一部分用户,大多都以有趣好玩为主,「游戏性」是最大的特点,所以情感化设计是非常好的选择,通过丰富的「体积感插画」用游戏的思路激发兴趣,让他们感觉有参与感,从而吸引他们「想看」并「点击」。

知识付费

而对于成年人来说,学习需求变成一种「插件思维」,能够快速学会,或者说是能够收获很多的干货,突出不枯燥、学会、能懂。这类的情感化设计相对于少儿学习插画,更多的突出主题所以,以更极简的设计形式。

有时候文字作为主视觉中心更加直观,整体设计风格可能更加简单,对于成年人来说,这种设计更能直达我们需求本身,更容易理解。

高端知识分享

对于这部分人来说,定位跟上面两类完全不同,从所处层级来说就不同。首先这类人,学习的可能就不只是干货了,更多的需求是职场环境带来的。比如,我怎么跟同事、朋友、下属更好的相处,如何具有更好的说服力,或者是想进修一下,就有了学习需求,基于「马斯洛金字塔」里的,这里学习需求可能也是更高层次的,为了体现自己的价值。

所以更关心的是,这是谁讲的课;通过设计情绪版,映射出当前课程的专业、严谨、课程的价值高,这些关键点。

课程的品质感的体现,颜色不能太多,插画设计元素少,更多的利用文字排版和少量图形来突出主题。

总之,根据所代表的用户来针对性设计。就好像剪头发,Tony 老师肯定不会给一个 20 多岁的年轻人理一个小平头;穿衣服也一样,你上班肯定不会穿个背心裤衩就去了,但在海边放松你也不可能穿个西装、牛仔,我相信大家都能明白这个道理。

2. 构图结构

良好的构图,目的是能够让用户易懂,首先结构要清晰、简单,主要构图比如:居中、左右。

居中结构

突出活动文案,居中构图是个很好的选择,不足就是体现不了有趣好玩的调性。直白说主要就是明确干什么。所以用户的视觉焦点会聚集在重心区域,忽略掉周围的东西,在设计的时候,周围元素主要是衬托,不能抢主视觉重心。

所以说运用插画风格的话,简单轮廓插画和剪影插画是最适合的。

设计的时候注意几点:一,主体物要突出饱满,太小容易画面太空;二,弱化辅助元素并不是要把它做的粗糙。

左右结构

左右结构分为两种,一种是左图右文,左文右图。两种构图的秘密在于,用户的浏览顺序是「从左至右」,如果图在左边,图在表意性不明显的情况下,我们需要看一遍文字,再看一遍图,这样图相当于重复浏览了两次;文字在左边就减少了重复阅读,提高了阅读效率,在运营推广「3秒原则」里,是首先要考虑的因素。而插画设计本身也是为了烘托气氛,表意性不是很明显,所以突出文案尤为重要。

所以,市面上大部分的学习知识类左右构图的,更倾向第二种左文右图。

左右构图受限于屏幕显示内容,所以,有一个明确的主体物至关重要。比如:像 VIPKID 和哒哒英语,会有一个自己的 IP 主形象,比较生动突出了品牌特征,还能让用户有代入感;还有像一些知识分享的,就会有一个明确的讲师或者人物,体现专业权威性,在设计上一切都以突出主人物来展开,就不要设计太过于复杂。

不同于电商的模特,主人物首先穿着上不能太花哨,要正式;周围装饰上不要太浮夸,要精简,甚至像高端知识分享的,背景就一个简单颜色来衬托。

衍生结构

还有以上面构图衍生的构图形式,比如倾斜构图,受限于 banner 尺寸高度,过大的倾斜角度会让画面失衡,负空间留白不均,会让画面不协调。

构图比例合理

注意画面整体构图比例,文案占比永远都是大的,不要让主要画面辅助元素过大抢了文案的风头,因为即使图形辅助再精彩,用户更关心的是「你能给他看什么」。

文案和辅助元素大概是六四开,黄金分割比例能让焦点更多的关注内容,有些小伙伴可能在做的时候过多的沉浸在放大的画布里,由于没有直观感受,错误的预估当前构图的合理性,所以做图的时候多缩小画布离远看是个非常不错的方法。还有一个就是,做完了 banner 导出图片,双击打开图片,把图拖小到无法拖动为止,再看当前实际尺寸大小,用实际尺寸来检查。

更多构图形式:《文案超多的海报设计该怎么排版?16个实用模板送给你!》

3. 文案文字

文案选字

文字的选择也是衡量当前产品用户定位的标准,首先文字结构不能太过于复杂,K12 教育因为本身用户年轻化的特点,字形简单而且饱满有趣,所以一些艺术手写可爱字体比较适合。

免费商用可爱字体推荐:沐瑶软笔手写体、站酷快乐体、郑庆科黄油体、站酷小薇 LOGO 体、锐字真言体。

其他可爱字体推荐:汉仪唐美人、汉仪糯米团、汉仪铸字童年体、汉仪小麦体、方正胖娃体、方正字迹新手书、造字工房童心、文悦方糖体。

如果是高端知识分享和知识付费,体现高端。文字就要简单,字形不要那么随意,一些黑体和简单的衬线体就比较合适。

免费商用黑体衬线体推荐:思源黑、思源宋、站酷文艺体、方正书宋简体。

其他黑体衬线体推荐:汉仪瑞意宋、方正清刻本悦宋、方正兰亭、造字工房朗宋、造字工房黄金时代体、造字工房尚雅体。

文案排版

当用户人群比较年轻,意味着所有的呈现方式都要直接,文案精简并且排版直观,提炼关键主标题,信息层级要拉开明显,如果信息层级不清楚,识别性是很差的,先看下面的案例:

看这两个,明显右边的对于我们识别,和对当前功能的认知更清晰,还有一个明显的视觉引导,突出了最主要的交互点;而左边的由于信息比较密集,导致我们无法短时间反应出关键信息是什么,这是比较糟糕的,运营同样如此,而运营比较尴尬的一点是,如果用户看不懂或不感兴趣,是根本不会点击、不予理睬的。那么流量入口的意义就没有了,设计的再精美,都是一个非常差的作品。

提炼文案是很有必要的,下面两个同样的设计,右边对于文案的认知就更明显。

有的时候往往文案的关键信息比较多,我们在排版的时候第一个重要点,就是排版怎么拉开信息对比,同时又让排版紧凑?有时需要增加一些特定图形,或按钮。但是又会考虑,加了这些特殊图形和文案又显得相对独立不整体;还有就是关键点该怎么取舍,强化那些文案、弱化哪些,或是主文案是重要的,同时关键的数字也要突出怎么办?

左图,左边主文案放大了关键点,由于右边文案文字比较粗,所以层级拉开还是不够突出,如果想拉开对比的话那就让他们截然不同。右图,字体选择上拉开强弱,让右边的文字比划选择细一些;左图的关键数字不够突出,通过提亮改变颜色,来强化;按钮在左边画面显得太独立,和文案没有形成统一关系,反而按钮看起来变得要比文案重要,那么把按钮插到里面。

现在所有的信息,一环插一环,并且突出的文案明显,关键数字也明显;最后让他们整体在画面构图中面积比例放大,改版后是不是舒服很多。

还有一些小伙伴可能觉得亲密性原则不就是距离相近么,然后没有把控好各个部分的文字距离,导致反而该拉开的没有拉开,该近的没有近。

上图这个案例里,主文案分为了两行,但左边由于主文案行距比较宽,而跟辅助信息的距离太近,导致亲密性不够,而由于副标题文案又比较孤立,上半部的信息和下半部信息太散,整体统一度不够。

右图改进后,调整合适行距,并且加装饰线,协调一下辅助信息比较短的问题,同时也起到分割的作用让上下文案有关联和统一。

文案排版的其他细节还有错位排版时,注意错位的大小,太大会丢失掉排版的平衡性;注意文案排版对齐,往往有的时候不注意,会让你的作品看起来不够精细;文案做倾斜处理的时候,一般情况都是往右边倾斜,第一,右边都是我们的主要习惯方向;第二,往右可以很好的把用户引导到关键信息上,这些也是做 banner 排版里经常犯的错也是要规避的一些坑。

4. 颜色技巧

颜色倾向

如果是代表年轻化,多用绿色和黄色,绿色代表活力、生机、积极向上;黄色系代表温暖、希望、舒服。

这两个颜色由于是临近色的关系所以也会搭配出现在画面中,色环 90° 角的颜色搭配所以是最舒服的配色,还有就是颜色对比非常和谐。

由于蓝色是绿色的邻近色、是黄色的对比色,红色是绿色的互补色、黄色的邻近色,所以绿、黄、蓝、红这些会在画面中组成主色、辅色、点缀色。

注意协调好每部分颜色之间占比,主色 60% 左右、辅色 30% 左右、剩下的辅助色 10% 左右。

如果是代表科技、互联网,就会以蓝色为主,颜色也不会像上面那样丰富,颜色体现的设计也没有那么活泼,代表冷静、自然、科技。

一般画面在2-3种颜色,以蓝色为主,再搭配紫色。因为紫色和蓝色是邻近色,不会像暖色调一样太冲撞,所以我们经常会看到蓝紫这种「好基友」的搭配。

知识分享类,分为普通的讲师分享和高端知识分享。讲师分享颜色要亮一些,颜色搭配大概是 1-2 种。

而高端知识分享,要体现知识的稀缺性和专属感,代表尊贵、品质、价值,颜色大多用暗色或消色(消色就是黑白灰),大概也是 1-2 种。

颜色方面我总结几点坑需要避开的:一,如果用插画表现,一定要避免颜色的灰和脏,因为学习代表着积极向上的,灰色不适合。颜色选取的时候大概要避开「颜色警示区」的位置。

二,插画风格避免选择紫和一些冷色调,以暖色调为主,才能贴合情绪版定位;三,同样的道理,颜色不要过于艳丽、过于刺激,反差明显了,反而阅读体验不好,影响观感;四,所有的颜色最终都要定位到主题上,做完后,反向推倒检查一下,颜色呈现符合当前文案定位吗?符合面向的用户人群吗?根据主题当前配色合适吗?

更多电商配色方法:《这是一篇不看会后悔的配色干货》

5. 小结

最后我想说的是,所做的东西把自己当成模拟用户自检一下,自己如果看到这个 banner 会点击么?会吸引到你么?能直观感受到么?会让你舒服么?如果连自己都无感,那是相当失败的。

如何使Banner中主体物更突出

运营专题在设计的时候,我们要考虑的是针对运营需求,给特定需求的用户传达零成本阅读体验,很多设计师做的 banner 画面特别乱,原因是画面中没有突出主体元素。

所以在 banner 设计上要考虑贴合当前传达的主题,所谓设计的「言之有物」。下面来详细的谈一下运营设计时如何突出主体元素,其中的言之有物。

运营活动最终想给用户快速传达文案信息,也就是「三秒阅读」体验,配合辅助文案的主体图形更能方便用户去理解。

可以看到下图左为了让画面丰富,设计师往往会加一些辅助元素或图形;而图右糟糕的元素添加反而会过度设计,干扰用户对于运营活动本身的理解和其表意性。

那么,如何突出视觉主体物,而达到最理想的设计作品的表意性呢?

我们从以下五方面细谈:

1. 图形化辅助元素

流畅线条的运用

我们在看音乐类运营 banner 的时候发现线条运用非常普遍,特别是利用 illustrator 里的「混合工具」来实现两条线之间的复制混合。

人物涂鸦剪影

往往为了表现特定的主题:比如年轻化、个性化,通过错位移动,添加亮色来使人物突出,往往更多的表现在:音乐、设计、嘻哈接头文化的电商运营宣传中。

这类设计个性鲜明,所以做之前考虑好,所要传达的特定的人群是不是符合当前的审美认知。

简单几何形状

有时候为了让传达主题更加明确,简洁化设计很有必要「少即是多」,所以比如学习和知识付费类的设计,干脆就用简单的圆形、方形、波浪曲线。

下面这个案例,设计者为了使这几个人物不会太散,用圆形包裹,目的也是为了更加整体,试想一下,如果把圆形去掉,人物不仅会显多,画面也显得既单调又乱。

立体几何载体

让风格调性显得品质高,同样让设计少而精。需要注意的是,品质感高逼格的设计所用的图形相对要规整一些,尽量不要显得太随意,多用方块形状和立体几何载体。

比如网易严选,为了突出「所卖东西都是精挑细选」,会采用立体几何载体衬托的方式,所表现的就是「隆重和百里挑一」,我们不一样~(会唱的朋友们一起唱)

多边图形

运用模特表现的时候,高品质感会用一些规则多边形,比如:四边形、多边形等。多边的形状会给我们带来稳重感,「尊贵感与众不同」往往是这类商品想传达给我们的。

不规则流体

促销类电商营造促销的氛围,激发购买欲,会用到多色彩的不规则流体,目的为了传达「降价、折扣、满减、超值、限时」等 ,往往会为围绕主体物四周,突出主体元素。

小结

图形化元素是最简单也是最实用的一种突出主体元素的表现方式,不管是用哪种,一定要想明白所表现的主题:符不符合当前主题;推广所属对应的用户群体:心理认知上能不能赞同;满足这两点,所加的图形才有意义。任何图形都是为了辅助突出主体元素,记住这一点,你就不会盲目的进行设计。

2. 文案装饰衬托

文字铺底

直接把相关文字铺底是最常见的一种方式,用当前所对应主题的人物名字、相关文案、对应英文等。

文字与主体穿插

利用文字与主体的穿插营造出空间感,也是在平面设计中经常用到的手法,同样也是在保证文字基本的识别度前提下。

注意文字颜色与主体颜色之间要拉开反差,不要糊成一坨,就适得其反了,适当的时候加一点点阴影还是很有必要的。

小结

不管是什么形式,所加的文字要有意义,跟主题相关。任何加的文案一定要能衬托主体物,也要有很强的表意性,毕竟文案才是最重要的。

3. 颜色对比的运用

主体物吸色衬托

从主体物上之间选取,作为背景颜色搭配,来衬托主体物简直不要太完美,前提是主体物的颜色相对够和谐舒服。需要衬托的背景颜色相对要弱一点,以突出主体。

颜色对比

我们一想到颜色对比,马上想到「红配绿赛狗屁」这句话,这句话的意思不是说红配绿不行,而是说错误的红配绿不行,听不懂啊?来,举个栗子…李子…梨子…例子!

左图的红绿颜色占比可以看到是比较平均的,大概1:1的比例,但是红色作为一个比较刺激的颜色,颜色很鲜艳,如果搭配的绿色也一样饱和度很高,两个撞到一起没有一个突出色,画面就不会那么和谐了。

右图如果我们把红色的占比相应的减少,饱和度不变,而绿色降低饱和度,从而面积占比增大,起到衬托的作用,画面之间是不是舒服很多。

下图其他的颜色对比同样如此。

小结

颜色对比的口诀是:主体如果是亮色,背景就用冷色;主体用重色,背景用亮色;主体用纯色,背景用灰色;不管哪种对比,主体物的颜色一定是面积最小的那一个,无论如何拉开颜色对比反差是王道。

4. 主体物局部打光

人物面部打光

人物面部是最容易辨识,也是视觉焦点部分,所以让面部从画面凸现出来尤为重要,让光源聚焦到脸部,主体人物显得更加有质感和饱满度。

物体亮部打光

物体和人物相比相对简单,亮部高光部分为视觉焦点,让物体显得有质感,只需要给亮部特殊光源即可。

小结

光线能在突出主体物的同时,让构图更加丰富和饱满,切记光线不要过亮,看起来会很不舒服。

5. 主体元素摆放技巧

人物截取范围

截取摆放人物的时候注意,为了让视觉焦点集中、有辨识度。具有代表性的人物和明星一般截取一半左右,大约胸部以上部位;而电商模特为了展示所卖衣服,一般露出大约三分之二。

万万不要切头部

让人物完美的呈现在画面之中,让画面能够看起来舒服些,构图也相对完整,反之把头部一刀切,会使画面负空间变小,构图拥挤,而观看者对于人物的识别度也随之降低,阅读成本变高。

多人物摆放要求

多人物组合时,整体人物处理要基本保持一致,特别是眼睛视线要尽量保持统一的视觉基准线,不然会显得杂乱不堪。

多物体的摆放

表现美食产品的时候,文字居中构图,物体散点摆放要注意,角度的统一,统一俯视角度,不要有俯视有平视,保证统一度。

6. 案例带练示例

案例分析

这是一个小伙伴做的医美类的运营 banner,当看到这个设计的时候我的内心是崩溃的,我们分析一下问题。

问题一,首先主体物没有突出,主体人物偏灰,背景也灰;问题二背景太乱,没有视觉焦点;问题三,文案识别度完全丢失掉了,排版也太乱;好下面我们来改一下。整体看下来,并没有表现出医美要体现的「变美」,用户完全没有视觉感受。

调整改动

前后对比

最后我们来看看对比效果,是不是好很多。

无论什么样的设计,加什么样的元素,目的只有一个就是要有理有据、有道理,所有的运营设计都是为了辅助主体文案。不要让你的设计无用,或者减分,把设计元素最大化发挥它的作用才是设计的最终目的,你就说是不是吧!

Vue 中 axios 拦截器的封装

seo达人

在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。他有很多优秀的特性,例如拦截请求和响应、取消请求、转换json、客户端防御cSRF等。

一 . 安装



npm install axios;

1

二 . 引入

在项目的src目录中,新建一个request文件夹,然后在里面新建一个http.js和一个api.js文件。http.js文件用来封装我们的axios,api.js用来统一管理我们的接口。

三 . 开始封装



在http.js中引入axios . vue及其他

import Axios from 'axios'; // 引入axios

import { Message, Loading, Notification } from 'element-ui'

import vue from 'vue';

1

2

3

http.js文件全部代码如下:



import Axios from 'axios';

import store from '../store';

import { Message, Loading, Notification } from 'element-ui'

import vue from 'vue';

// 环境的切换

if (process.env.NODE_ENV == 'development') {

  Axios.defaults.baseURL = "http://10.230.39.58:33390/devops";

}

else if (process.env.NODE_ENV == 'production') {

  Axios.defaults.baseURL = "http://10.230.39.58:33390/devops";

}

// request请求拦截器

Axios.defaults.withCredentials = true

vue.prototype.$axios = Axios

//请求超时时间

// Axios.defaults.timeout = 100000;

Axios.defaults.headers.get['Content-Type'] = "application/json"

Axios.interceptors.request.use(config => {

  const Basic = sessionStorage.getItem("basicParam")

  if (Basic) {

    config.headers.Authorization = Basic ${Basic};

  } else {

    console.log("无校验值");

  }

  return config;

}, error => {

  Promise.reject(error);

})

// respone返回拦截器

Axios.interceptors.response.use(

  response => {

    if (response.data.code !== 200) {

      Notification.error({

        title: '错误',

        message: response.data.message

      });

    }

    return response.data;

  }, error => {

    // Notification.error({

    //   title: '错误',

    //   message: '系统异常'

    // });

    console.log('err' + error);// for debug

    return Promise.reject(error);

  }

)



export default Axios;



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

api.js文件全部代码如下:



import axios from 'axios';

/

  封装get方法

 
@param url

  @param data

 
@returns {Promise}

 */



export function fetch(url, params = {}) {

  return new Promise((resolve, reject) => {

    axios.get(url, {

      params: params

    })

      .then(response => {

        resolve(response.data);

      })

      .catch(err => {

        reject(err)

      })

  })

}





/*

 
封装post请求

  @param url

 
@param data

  @returns {Promise}

 
/



export function _post(url, data = {}) {

  return new Promise((resolve, reject) => {

    axios.post(url, data)

      .then(response => {

        console.log(response,

          "response");



        resolve(response);

      }, err => {

        reject(err)

      })

  })

}



/

  • 封装patch请求
  • @param url
  • @param data
  • @returns {Promise}

    */



    export function patch(url, data = {}) {

      return new Promise((resolve, reject) => {

        axios.patch(url, data)

          .then(response => {

            resolve(response.data);

          }, err => {

            reject(err)

          })

      })

    }



    /**
  • 封装put请求
  • @param url
  • @param data
  • @returns {Promise}

    */



    export function put(url, data = {}) {

      return new Promise((resolve, reject) => {

        axios.put(url, data)

          .then(response => {

            resolve(response.data);

          }, err => {

            reject(err)

          })

      })

    }



    在main.js中引入api.js



    import { _post, fetch, patch, put } from './utils/api'

    //定义全局变量

    Vue.prototype.$post = post;

    Vue.prototype.$fetch = fetch;

    Vue.prototype.$patch = patch;

    Vue.prototype.$put = put;

    1

    2

    3

    4

    5

    6

    最后在组件里直接使用



     this.$post('/api/v2/movie/top250')

          .then((response) => {

            console.log(response)

          })

          



    其他方法用法相同




v-for生成多个div并给div中的组件绑定值

seo达人

实际业务比较复杂不便展示,写一个简单的demo记录此功能



 



遍历此div:



<div v-for="item in demoArray">

    <input type="text" v-model="item.name">

    <el-switch class="exio-switch" v-model="item.status" active-text="开" inactive-    text="关" active-color="#13ce66"></el-switch>

    <button @click="showInfo(item)">查看</button>

</div>

js代码:



new Vue({

    el: '#app',

    data() {

        return {

            demoArray: [],

        };

    },

    created() {

        // 生成模拟数据

        for (let i = 0; i < 5; i++) {

            let e = {};

            e.name = "div"+i;

            e.status = true;

            this.demoArray.push(e);

        }

    },

    methods: {

        showInfo(item) {

            console.log(item.name);

            console.log(item.status);

        }

    }

})

页面展示:







修改一条数据:







验证双向绑定结果:







为了解决不确定数量的数据(数据来源可能是接口等)的展示和操作,将每条数据作为元素放在数组中,通过数组中元素的属性来进行双向绑定。



整理的仓促,emmm,收工




我以前在阿里巴巴的流量方法论

雪涛

作者从自身经验出发,结合实际案例,分享了流量获取过程中非常有价值的知识,值得运营人细读精读,一起学习。

大家好,我是国平。我做流量已经有16年了,2010年之前主要在阿里巴巴国际站负责免费流量增长,把海外B2B免费流量的日UV做到几百万。后来成立了一家乙方公司叫光年实验室(以前叫杭州光年),是携程、阿里云等40多家主流的大型互联网公司的流量顾问。另外这些年也没少折腾其他项目,其中做过电商(外贸独立B2C网站)、做过电商系统(类似有赞)、 做过移动端APP (社交方向)。

来“群响”这段时间,只要能参加的聚会都参加了,听过大家分享很多非常有意思的流量玩法。先不说不同行业的“隔行如隔山”,就是在流量领域,可能有很多种细分领域,大家之间的资讯都是隔离得很厉害的。流量的渠道和玩法是永远在变的,不过也有一些不变的东西,如平台和内容创造者的博弈、大家仰视平台的心态(其实没必要)、以及各种流量玩法的底层模式等。

我首先分享的是过去一个很主流的流量渠道–搜索引擎,看看在现在这个移动互联网时代和新媒体时代还能如何获取流量。

第一个议题就是:现在是否还值得做搜索引擎营销

结论是:值得做,不过如果不了解现在国内百度的现状生态,99%的人ROI一定会很差的。至于海外的Google,它依然是大部分人的第一大流量来源。

首先说为什么值得做。

大家可能不知道的是,在搜索引擎,也是65%以上的流量来自移动端,所以不要认为搜索引擎是PC流量的代表。百度的DAU是没有下降的,DAU在3亿多,大家在手机上也是会搜索的。

我喜欢把流量分为“搜索流量”和“社交流量”,分别对应“人找信息”和“信息找人”。我的观点是这两种大家获取信息的模式没有主次之分。

只是在国内,百度的相对市场份额是一路下滑的,先是淘宝、去哪儿等分走了很多垂直搜索的流量,接着又有微博、微信、抖音等社交平台相继崛起,百度没有以前那么重要了。

我们服务的好几家头部互联网公司每天的总UV(包括APP)当中,还有超过四分之一的流量来自搜索引擎。 客户不能拿来作为案例,不过有公开的渠道可以查到的一个例子:知乎某段时间的每天的总UV有四千多万的情况下,来自搜索引擎的UV有一千三百万。

搜索引擎流量的转化率,一直都是所有流量渠道里面最高的。因为社交媒体的流量的性质是“逛”,而搜索引擎流量是主动“搜”。搜索引擎流量在关键词和内容匹配的情况下,有不少做到过10%左右转化的例子。

然后搜索引擎流量相对稳定可控,而且像SEO自然排名这样的流量还不要花钱,这也是头部互联网公司比较重视这块的原因。不说它们,就是那种中型的以卖流量为商业模式的互联网公司,如融360、土巴兔就是其中的代表,每天都从百度获取百万UV以上SEO免费流量。

最后就是目前还存在一些以前很少有人知道的红利,这是今天后面要讲的重点。

那为什么说大部分人做搜素引擎流量的人ROI会很差,要从自然排名(SEO)和 竞价排名 (PPC)两块来看所谓的内情。

搜索引擎营销分为自然排名和竞价排名两块,自然排名就是非广告排名,是由系统按照一定的算法来决定谁应该排在最前面。竞价排名就是买排名(PPC。即Pay Per Click),根据你花钱的多少以及用户更喜欢谁的广告把你的广告排在前面去,当然在百度主要是看谁花的钱多。

对于自然排名来说,它的回报周期应该是一年以后,而很多人期望几个月就有好效果;然后是整个行业的无论是甲方公司还是乙方公司都没有很专业的人,搜索引擎营销服务商行业总体来说是一个逆淘汰的行业。还有百度自己的页面在搜索结果中占了快三分之一,而剩下的流量头部效用明显,也就是只有大网站才能获得不错的流量;在这么一种糟糕的情况下,百度对优秀内容的判断严重失控,很多人通过一些作弊的方法快速获取了很多流量。

而竞价排名这种花钱买排名的方式,对于很多人是鸡肋一样的存在了。我个人觉得百度的价值观不是很正,他们在一开始就用错误的方法在引导大家投放广告。 这个可能有点危言耸听,也就是在指责百度为了自己的利益,这十几年以来一直在误导大家去花更多的钱。

这是由于竞价排名的模式就决定了,只有大家都共同认为某些关键词的流量很大才会去竞争这个词,而大众都是拍脑袋来认为哪些词重要与否的,比如任何一个卖口红的都认为“口红”这个词要是不投的话,好像搜索引擎流量就不要做了,百度也就顺水推舟让大家用这种思维模式去投广告。

具体案例:我给大家两张图,假设客户是在卖“阿胶”:

为了让大家有直观的感受,我先考一下大家:假设你是这个卖阿胶的商家,你去百度投广告,你们会决定买什么关键词呢?

 

 

这张是曾经百度给客户培训的关键词选词方法:

这种方法就是大家去定义一些和你的业务相关的核心词,如阿胶、滋补品等,再定义一些前缀和后缀等,然后再排列组合。这样出来的词就是:

上海阿胶电话

北京阿胶电话

上海阿胶网站

……

由于大家选词方法一样,就会产生竞争,一定可以把少部分大家能想到的词的价格抬上去。

而这张是我们一直以来用的关键词选词方法:

这里是通过很多数据挖掘工具,先把整个行业用户正在搜索什么都列出来,必须要穷尽整个行业,越多越好,然后按照核心词再分成不同的组,这个时候用户的需求就明明白白列在你面前了。

从这份数据能看到,“阿胶”这个代表整个类目的词语,每天的搜索量也只有8078。搜索引擎上所有的行业都是这样的,用户搜索的80%的词,字数都是很多的。其实大家想一想也不难理解,即使一个初级网民,也明白用“阿胶”这样的词语是搜索不到自己想要的东西的,大部分来搜索引擎搜索都带有明确的需求而来,大部分人的需求都有个性化和独特的地方。

但是在商家投放广告的时候,就陷入了一个思维上的误区,以为“阿胶”这个词语特别特别重要。实际上,一个品类重要,不意味着代表这个行业的某个行业关键词就重要。

比如“iphone11 价格“这个词语的搜索量远远超过”手机“这个词语;”163邮箱“这个词语的搜索量一天是十多万,而”免费邮箱”这个词语的搜索量是三千多。“小说” 这个词搜索量不高,“TXT全本小说下载” 这个词每天有160多万的搜素量。

百度也就没有纠正大家的误区,让大家按照这个思维定势去买关键词。十多年来,很多人也是这样按照这个误区在做着SEO。

第二张图是我从百度于2019年10月28日获取的数据,每天百度上真实地搜索“阿胶”相关的关键词基本都在这里了。无论你怎么想破脑袋,你也想不出用户是这样在搜索的。图二的数据,即使有些从事了10年搜索引擎流量运营的人,从来都没看到过的。

我前面所说的流量红利,就是这么多年以来行业里都在用错误的方法做搜索引擎流量,所以以至于到了今天,搜索引擎上还有一大半的流量没有人要的。我再发几张图,大家自行去搜索就知道了。

(这里的日搜索量是指查询这个数据的那天再往前30天的流量总数除以30天,就得出最近一个月的日均搜索量。数据是有时效性的,所以要用的数据。)

以下是稍旧一些的数据。

投资理财:

汽车行业:

第二个议题:搜索引擎营销是一个什么样的流量世界

搜索引擎营销已经有一帮人做了十多年,现在来看这是一个什么样的流量世界呢?

首先搜索引擎是“长尾理论”的最佳实证, 在搜索引擎做流量要深刻的理解长尾效用。Google曾经公布过一个数据:google每天的十几亿次搜索中,如果匹配用户搜索的那个几个词语,有15%的搜索词是过去1年从来没有人这么搜索过的。比如类似搜索 “ how to make an automatic door in minecraft ”,这样的词的组合, 每天有15%的词过去1年都没人这么组合在一起搜索。这样的情况,不光Google和百度是如此,淘宝、小红书、微信搜索里都是这样。

如果真是情况是这样的,你根本就没法做到说我要“做某几百个词的排名”这样的事情,因为每天词语都在变。我看过太多团队其实就拿着几十个自己想出来的词在那里做投放和做SEO。这种情况十年前是这样,现在也还是这样。

很多人问过我怎么找搜索引擎营销方面的人。我的建议是只要他们问面试者一个问题就可以结束面试了。那就是问对方在做搜索引擎营销的时候目标关键词是多少个。

分这么几个水平段:

  • 少于1千个词—-还没有入门;
  • 1千到3万个词—-大部分是标准教程培训出来;
  • 3万到10万个词—-只有这个阶段才能考虑录用 ;
  • 10万到50万个词—-对于一个非常小业务范围的品类是合格的;
  • 50万到500万个词—-这样的人大概一年都面试不到一个。

在搜索引擎上,找到50万个属于某个行业词绝对是一种很强的能力。实际光找足50万这个数量还不够,如果要做好投放,还要找到最佳性价比、鲜的词。现场如果有在投放搜索引擎广告的人,对比看一下自己公司后台有多少关键词在投就知道你们目前所处的阶段了。

搜索引擎其实有广泛匹配的机制,但是如果你投的词太少,广泛匹配机制也并不能挽救你,而且这样会有很多没有转化的词在浪费钱。

现场目前做的是新媒体行业居多,假设你是一个做美妆的,你的目标就是要小红书上的美妆KOL推广你的产品。假设小红书官方在后台把所有的美妆达人都拉一份数据统计有2万个,而你们现在只有20多个KOL在投,你的对手却有1000多个。(这里先忽略1000多个KOL的操作成本,和红人KOL营销不同,买某个词的流量在搜索引擎上操作成本很低。)这个和在搜索引擎上做投放是一模一样的。

类似的,不知道大家同不同意,现在还在找大V合作的,如果是做效果广告的话,就是那种以前在搜索引擎上买“阿胶” 这种关键词的人,ROI很低。

阿里巴巴的流量增长团队是2002年成立,现在在搜索引擎这块的投放水平可以看一个网页:https://www.alibaba.com/showroom/showroom.html

大家点一下A字母,这里都是以A开头的关键词,一页是120个词,A字母下有22429页。A到Z一共是2千多万个词。

以前这是我负责的,我能确定每个词每天的流量都达到了一定的搜索量,也就是说都是比较重要的词语。那时候我们的口头禅就是“加词等于加流量”。记得当时从国外一家专门卖词的公司买了3万多个优质的词,然后我们一个季度的KPI就完成了。

顺便提一下, 其实这种方法也可以用来做产品。

比如旅游行业,当时有个知名网站,我们把整个旅游行业的词挖掘到了大概有500万左右,然后像前面那样分组分类,就知道了这个行业大部分用户的诉求。

当你在搜索引擎上能分析的词达到500万的时候,已经基本上是全量数据了,这些数据至少可以代表这个行业一半以上的人的诉求。这可以成为大数据的一次很好的应用。后来通过这批数据,发现旅游行业只要你去做攻略类产品是一定会活得不好的,因为攻略类需求占比排在很后面。结果现在大家也看到有些做攻略类的APP至今挣扎在盈利边缘。

然后大家看前面的汽车行业的词库数据,从2015年起, “SUV”和“七座”一直是这个行业真正的热点,但还是很多汽车互联网公司不知道这个。

然后看在阿里巴巴的一个页面:https://www.alibaba.com/showroom/mp3.html

这里列出了MP3的一些属性,有按“功能”、“屏幕” “充电时间” “风格” 和 ”颜色”, 这里的属性分类以及每个分类里的那些项目,完全是按搜索引擎里用户的搜索量从高到低排序的。这样做的结果就是转化率和粘度非常高,比当时产品经理做的页面提高了4倍。

具体很多细节可以在线下聚会可以分享。

第三个议题:怎么做好SEO和PPC

做好SEO和PPC最重要的事情就是关键词挖掘,不做这个事情基本是没法搞好搜索引擎流量的。大家要明白这么一个场景:在搜索引擎上,你的流量是通过一个个的关键词作为载体传播出去的,没有太多词传播你的流量,总的流量怎么可能多呢。

具体的关键词工具,我先介绍我们开发的一个:

https://mp.weixin.qq.com/s/M1VCCFqNb9xSBnmD2hktFg

一个行业里,光靠人脑是想不出这么多词的,这个工具可以帮你自动挑出很多词。光年实验室正在做一个SAAS平台,还有更多的关键词工具会出来。

注意一点,词语的数据一定要有时效性,最好就是最近几天的。前面说过Google的15%的搜索词是过去1年从来没有人这么搜索过的,如果数据没有时效性是没什么意义的,很多一个星期前流量大的词现在可能就不是的了。

对于很多人来说,最能去执行的就是去百度做PPC投放。如果你们可以搞好关键词挖掘,百度对你来说依然是一个非常有红利的流量渠道。

不过要遵循一些基本规则:

1. 为了防止收不回成本,第一批投放的词必须是没有任何人和你竞争的

在百度,如果这个词没有人和你竞争,点击价格只要3毛钱就可以。

所以一开始的策略就是买别人没有投的词,我们所有投出去的词都要查一下有没有人在投,但凡有一个竞争对手就不投了。大家可能想不到的是,即使这样你竟然还是可以投很多词的。

2. 做好广告组和落地页面的优化

我个人觉得搜索引擎是最早教会国内互联网人什么是转化率、落地页、复购这些基本概念的,在它之后成熟的淘宝只是进一步把它普及给了更多的人。 而北美在90年代中期就有了第一波商业化的互联网公司,它们更早更系统的研究很多东西,可以去补课,比如《Landing Page优化权威指南》这种最基本的书。

很多淘系的培训,由于它是一个封闭系统,速成技巧居多,系统的东西不多。广告组和落地页面的优化,稍微科学地做一下改进,可能可以提升好几倍的ROI。

至于那种最基本的事情都无法做到的公司,比如:你们的投放人员投放的关键词少于100个;以及无论什么关键词的流量都跳转到首页等这种业余行为,应该立即关掉搜索引擎投放,去拓展现在的微信、快手和抖音等渠道。没有专业投放就只能放弃这个渠道了,但要我说这里真的很多流量没人要。

我曾经见过两家在海外竞争的中国互联网公司,同样的APP,一家的获客成本是1美元多,另一家是10多美元,而第二家一直以为本来就要这么多,直接决定了后面一家公司一年后在这个赛道出局。

不专业的投放就是在给公司放血,我见过很多不专业的投手害死公司。

3. 不要找外包公司,靠自己的团队打造自己的流量竞争力

特别是那种代为操作帐号的公司。这个句话得罪很多人,但是事实。流量获取、用户增长应该要成为一家公司的核心竞争力,怎么可能靠一家第三方公司拿到这个竞争力呢? 搜索引擎流量外包这是一个逆淘汰行业,好的公司已经出局。(像我们这样的顾问型公司也只适合成熟的流量团队)

例如现在上市的某家流量外包的公司,曾经我们在办公室把他们的方案当作笑话在传阅的。 当他们的收益来自于你投放广告金额的百分比的时候,你投放的金额越多,他们收入越高,利益相悖,怎么可能会有精细化优化的动机。由于甲方帐号太多、而这些帐号基本都是实习生在操作的外包公司不要太多。

以我有限的创业经验, 产品和流量,应该是要公司高管要花最多时间的部分。我这么多年看过很多好的用户增长团队,很大程度上他们成就了那些公司。例如,我比大家更早知道今日头条的张一鸣,在2006年他们做酷讯的时候流量是做得特别好,甚至有一种方法成了后来行业惯用的方法。

当时酷讯做火车票查询,他们从一个固定的火车查询数据里把很多站站查询、车次查询生成了几十万个不同的网页,而这些网页都命中了很多查询“上海到南京火车票”这样的流量,从前面的案例大家可以推算,这种流量偏偏是大头,而“火车票“这种太泛的词流量没大家想象的那么高,所以酷讯的搜索引擎流量是很好的。

这种做法即使是十年后被“欣欣旅游网“抄了一遍依然获得了大量流量。

操作方法具体看:http://huoche.cncn.com/

这种方法后来被总结为:当你的行业有一些从固有数据库能查询到的数据,请把它网页化,去命中搜索引擎的关键词,然后这些流量就是你的。

后来有人把QQ号码、邮政编码、手机号码、天气预报等等都网页化一遍,都是大量的流量。

最开始今日头条APP在推出后,一个多月就做了900万的装机量,这是擅长流量的团队才能完成的业绩。而“今日头条”这个APP早期对5千多个网站抓取内容再去做流量的做法,和早期站长的那些站群方式是何其相似。大家想想抖音这个APP本身是怎么火的,怎么可能没有流量增长团队在后面做了大量工作。

SEO这块,要充分利用百度把近三分之一的流量给了自己的产品这个状态。百度问答、百度贴吧、百度文库、百家号甚至百度网盘等等全家桶里,全部要有你的内容。当你有了上面那样的词库,词库里都是用户的搜索需求,搜索量哪些高哪些低已经全部告诉你了。然后再在百度这些渠道里铺内容就只需要一些常识,只要去琢磨如何把你的内容合理放上去就可以了。

最近的流量红利是百度小程序,这和以前的百家号一样,是优先排名的。我个人觉得这是百度最后一波红利了。

百度也给了很多大站很高的权重,如知乎、搜狐自媒体、CSDN(你没看错)等,这一点在海外的Google也是这样的趋势,这不是搜索引擎偏心,而是经过很长时间的进化,上面会聚集更多好的内容创造者。我们可以去上面铺内容并转化用户。

大家要放弃一定要用自己的网站去做流量的观念,流量肯定是越来越集中到头部去的,那种把自己的网站也要打造成流量中心的想法越来越不现实了,特别是啥优势也没有的小站。所以可以安心地做一个别人平台上的内容贡献者,在这些平台上贡献内容,转手再把这些页面拿去任何其他平台上去引流。我以前一直说的方法就是要“让内容在渠道中间流动”。

还是以“阿胶“为例,可以这样操作:

从上面的词库可以看出:“阿胶糕适合什么人吃“有2万多一天的搜索量,去百度一下这个词,我现在在杭州搜索,发现是一个广告都没有人投的。(不排除其他地方有或者当你看的时候可能会有)

这个时候,应该去知乎、百家号、搜狐自媒体、百度知道、百度小程序等等渠道里出现你的一篇软文,里面在推荐你的产品。这样做完后,你要和现在这些排在前面的网页去竞争排名,只要一些简单的SEO技巧比如“锚文本轰炸”或“外部链接”,甚至最原始的“关键词密度”,你排上去的几率非常大,然后这些流量就是你的了。当然最后,这个词如果被别人挖掘到,那也也会变成红海,所以你的应对方法就是去发现更多其他蓝海词语,或者直接硬抢也是没几个人在竞争的。还有,图片中那几个排名前三的百度问答,你即使现在再去回答一下也会有很多流量的。

这么多年了,百度依然还有很多流量没人要。这点百度其实是自己把自己作死的。你看,虽然百度让很多人出高价买了词,收入也很多,但是百度的很多流量没有卖出去。相当于流量还有很多库存,流量没有充分被商业化,而广告主却在高价流量中没有获得好的ROI,这是双输的。今日头条在这一点上就做得好很多,本来信息流的流量比百度还集中,头条的巨量引擎现在开始开发很多的功能让大家的投放尽量错开不要撞车。

如果你们是APP且内容很多,一定要找个前端工程师把内容网页化并做基本的SEO,可以白捡很多流量。比如今日头条的SEO在我看来还是做得不够好,内容也是重复的,但是应该在百度获得上百万日UV不是问题。

还有很多的技巧实在无法短时间说明白,影响SEO排名的因素有几十个现在一个都没怎么讲,但这些也并不重要,刚才提到的3个都是随便一查就能找到的技术。 这么多年,在流量领域有技术算法派也有策略派,最后都是策略派胜出。这点也可以给正在做抖音、微信、快手的人一些启示。

这里再顺便说一下,“阿胶糕适合什么人吃“这个词如果你有把握用3毛钱的PPC成本可以收回投资的话,直接买一轮流量先。

第四: 基于关键词和基于关系链的流量方法

接下来我跟大家分享一种我多年来积累的流量体系,这是我最想分享的,它是很多方法的来源。

我个人的观点,流量一直只有两种载体:关键词 和关系链。很多渠道里的流量传播都是这两个基本载体中的一种,或者是变种、混合。

这是我们以前在阿里流量团队的方法论,它的推导是这样的:

流量的背后,是我们大家对信息的需求,不管你是找一个笑话段子、还是看一篇教你做饭的文章、或者是纯粹无聊打发时间随便刷刷。

人类目前为止传播信息的模式,要么通过文字、要么通过人和人的关系。

这个在原始社会甚至没有文字的时候都是这样的,比如一个部落发现了猎物要去捕猎,这个信息也是通过大家早就形成的语言以及人和人之间的关系网传递出去。

而假设我们回到20多年前没有互联网的时代呢?也是这样的。

我是80后,经历过没有互联网的时代。我举一个例子,那时候我有一个亲戚在船厂工作,他听人说有一种水下焊接的技术,但不知道具体是怎么实现的。在今天面对这样的情况你搜索一下就可以知道。

但是在没有互联网的时代,他也有两种方法可以去解决这个问题:一是去一家尽可能大的图书馆去查资料,以前的图书馆有个重要职能就是大家去查资料的地方;二是去问他的师傅或其他朋友,通过他们的关系网去找信息。很有意思的是,Google这个搜索引擎就诞生在1996年两位创始人在斯坦福大学给校方做电子图书馆的基础上的。

图文、视频他们传播的时候一定要用关键词给他们做索引的,比如抖音的算法就是给每段视频和每个人打标签,标签就是关键词,然后把人的关键词和视频的关键词做匹配,这是属于变种。

我们先看关键词为载体的流量渠道。

搜索引擎、淘宝和APP应用商店是关键词主导的流量渠道,这个自不必说。即使微信这个以关系链为载体的流量渠道,它首屏的搜索流量也非常大,所谓的WSO(微信搜索优化)也有了一些成功案例。而在微信小程序搜索里,如果你搜索“股票”,有几千个小程序都写着股票的标题,但是你搜索“股价”,却只有3个小程序写着股价的标题,你只要是第4个,也能每天来很多用户。仅仅整个股票证券行业,至少还有上万个这样的词没有人去关注。

在美国,有组织统计过所有搜索流量和所有社交流量,是非常巧合的1:1的比例,前面说过:“信息找人” 和 “人找信息” 这两种大家获取信息的模式没有主次之分,这里就有第一个数据上的证明了。

对于我们获取流量的人来说:人多的渠道要多圈人,词多的渠道要多占词。

我用一个例子开启大家的用关键词做流量的视角。 有一家做家装互联网的公司是这样获客的:在搜索引擎上把这个行业最热门的几千个关键词都搜集起来,买了十多个QQ号码,然后每个QQ号最多可以建500个群,他们建立的大量QQ群的群名称都是那几千个关键词中的一个,有软件可以批量维护群的活跃度,所以当QQ用户在用这些关键词去搜索QQ群的时候,他们的QQ群排在比较前面。这样十多个QQ号码每天能让八千到一万左右的QQ号码加入他们的群,然后再用微信私域的方法转化用户。

关键词为载体的流量都可以总结为一个这样的方法论: 在任何渠道里做流量,都可以观察这个渠道里是不是有些流量是通过关键词分发的。如果有,就去抢以关键词作为载体的流量。

至于关键词的来源,百度是一个普及程度很高的搜索引擎,只要那里热搜的关键词,在你要做流量的渠道里大概率也是热搜的。你都要做到大批量占领你所在行业的关键词,我们以前阿里的流量团队把这个方法叫“关键词占领”。

比如:微信好物圈,这是一个流量通过关键词分发的渠道;你占据了一批好的关键词命名的圈子,你就天然获得大量流量。

比如飞聊,也是一样的通过关键词分发的渠道,如果你认为这个平台会崛起,是一定要去里面建很多你包含这个行业的热门关键词为标题的小组,以后小组火了流量就是你的。目前飞聊的DAU也有几百万。

比如抖音这样的算法分发的平台,如果你的视频都打上很多行业热门词的标签,额外获得很多流量不是问题,更别说抖音是可以搜索的。去搜索一些热门关键词,很多排在前面的视频流量很大,但是他们可能不是靠内容精彩获得的流量,只是靠标签命中热门词流量就可以。

你只需要笃定一点:只要人类还在用文字传播信息,“关键词占领”的方法就会一直有效。

还有就算花钱购买流量的渠道都是能让关键词发挥作用的,比如今日头条的巨量引擎后台是开放了用关键词定位人群的投放的。

关于这个信息流投放,很多时候我们投放信息流,时间点很接近、人群属性可能都是25-45女性、高收入年龄什么的,大家的定向条件其实高度集中,所以广告展现是要靠提价的。但假如大家是用关键词定向,就不会撞车这么严重,也能触达到很多平常大家触达不了的用户, 平台流量得到充分利用,广告主ROI更好看,是多方共赢的。

关于关系链的流量,我在线下听过大家分享过很多好方法,特别是内容驱动、私域社群的很多玩法等。有时候很有感慨的,今天大家做的很多内容十多年前也有一批人和你们是同样的心态和状态,只是平台变了,但很多讨论的内容都是如出一辙。淘宝当年用一种仰视平台(163/网易/搜狐)的心态去拉流量,今天又有那么多商家用仰视淘宝的心态去获取流量,想想很有意思。

和关键词的玩法不一样,关系链的玩法我觉得国内是远远领先国外的。

不过国外有一批同行也是做社交关系链流量的,他们比我们更早把社交关系链的方法系统化一些,他们是怎么做的呢?

这里插述一下,像微信公众号这样的平台我觉得其实是抄袭自Facebook。这个一个很另类的观点,我借这个机会说一下。

大家看一张截图,Facebook在2009年就推出了一个产品叫 Facebook Pages,如:https://www.facebook.com/pages/ (需要翻**墙)

商家、公司、公众人物、社群可以给自己生成一个页面,这个页面大家可以关注,然后如果商家发布什么消息可以更新到你的信息流上。这和微信公众平台是完全一定的定位和功能,只是早了4年多。他们很多商家在Facebook做营销也是要拼命涨粉的,如Amazon的Facebook Pages有了快3千万粉丝。

而2013年,现在这样定位的微信公众平台才正式进入大家视野。所以如果我们借鉴吸收国外同行的方法也有一些有意思的角度。

基本上那时候的方法论是这样的:如果传播流量的载体是关系链,那就去优化这4个点: 即,传播信息的人的数量、传播信息的人的影响力、传播信息的速度、传播信息的美誉度。

国内是把传播信息的速度做到了的,相信不用我复述那些方法。然后做各种帐号矩阵的人也是把传播信息的人的数量做得非常好了,比如至今微博上的很多明星的流量运营团队。

国内严酷的竞争环境造就了大家各种奇招百出。我分享几个我们做社交关系链流量的玩法,看看我们是如何按国外的社交流量方法论做国内的平台的。

在“传播信息的人的数量“上,我举快手APP的例子。

快手APP上官方是分均分发流量的逻辑,也就是你打开快手,会把你附近的一些人推荐在你的快手主页。为了迎合这种分发逻辑,我们肯定是要做多帐号分发的。比如直播是这样操作的:我们开发了一个自己的群播系统,长下面这个样子,

它的视频信号是用一个摄像头来拍的,视频内容输入这个系统后,可以把这个视频分发到无数个其他快手帐号上,每个帐号模拟不同的地理位置,这样只要一个直播内容就可以出现在全国各个不同的地方。

当然它也可以把同一个视频信号同时在快手、抖音、腾讯、斗鱼等APP上跨平台同时直播。快手是不太喜欢相同的内容的,所以这个摄像头拍摄的画面的背景是绿幕,这个系统可以实时渲染出不同的背景,这样看起来就是不同的内容了。(没有破解app等非法操作。)

在社交关系链的传播方法里,环境很恶劣,你是被逼着要这么做的,在场的大家应该都知道,因为其他人会去布局更犀利的事情。有些我们都知道的大公司,私底下也很多类似的操作。在其他条件相同的情况下,如果传播人数别人比你多个几十上百倍,你也就没法安心地靠内容驱动了。

在增长黑客的很多成功案例里,以及现在我们在市面上看到的成功产品,有大量依靠人数取胜的例子。

那怎么做到“传播信息的人的影响力“ 呢?我们打造了这么一个系统,这个系统的原理和“企查查”的原理差不多,就是打造一个聚合爬虫(合法的爬虫,从不同的数据源爬取数据聚合在一起),这样做的结果就是:指定任何一个行业,每天都能找到几千个这个行业下的优质KOL,并有他们的个人微信二维码等联系方式。

如下图就是金融领域每天抓取到的数据:

会按各种指标给每个KOL打分,分数低于一定的值就先不考虑联系。但还是每天都有这么多的KOL,这又怎么来大量联系呢?我们也偷了个懒,是用企业微信批量联系的。

由于企业微信一天加上万个人都不是问题,所以我们就做了一套企业微信的群控系统,可以批量把这些人加为好友,然后群发话术来沟通,粗筛一遍后再人工沟通。在别人都在批量“洗”终端用户时,我们在批量“洗”行业内的KOL。

以下是我们的微信群控软件的演示版,企业微信类似:

大部分人都没注意企业微信的功能,这个企业微信大家一定要重视的,非常好用。过一段时间我们会推出一个企业微信的工具出来。

很多人不知道企业微信官方就有群发接口,不要再用那些山寨的群发功能了,然后每天加人不会轻易被封,加人还没有总数限制,而且你能相信腾讯官方在企业微信里竟然还开发有“活码”这种东西吗?

从策略上来说,如果腾讯官方专门希望你用企业微信来做私域,你哪有还不赶快用的道理,只会越来越顺应大家的需求的。只是注意一点,企业微信目前还没有朋友圈,微信群功能也受限(有消息说11月底都会放开),所以一定是要探索一套新的不同于个人微信私域运营的流量玩法。

这种玩法还特别适合产品冷启动,大家在冷启动的时候最缺的就是种子用户,这类聚合爬虫的方法可以让你迅速获得你想要的用户从而冷启动成功,我们自己就有过很多冷启动成功案例。

说起这个群控系统,我们做了两套不同技术原理的系统。大家知道基于xposed的群控系统在今年618的时候已经被微信严打,以前我们也认为xposed这种群控方案侵入性太强,我如果是微信官方也会非常不喜欢别人把我的APP改得乱七八糟。两套系统用的是别的解决方案,只是用它替代人工,不要非法破解使用就行,目前这两套方案都是比较安全的。

有些时候我们用这些系统能形成比较大的优势,但是越是这样我们反而越会想办法做好内容。毕竟我们是从大平台出来的,我们并不想在任何平台出于搞流量的需求而制造内容垃圾的。

为了防止带偏大家,我再多说一句。对于很多这样做流量的方法看起来很激进,但做起来是有底线的。应该要像阿里巴巴内部的那种做事风格,那就是:初心要正,但是做事要狼性。

我们从事的互联网行业是个信息产业,所以要尽可能地“传递高质量的信息”,把内容做到尽可能地好。而在分发这些内容的时候却要无所不用其极地、想尽一切办法去传播这些内容。

最后我们再来说一下“传播信息的美誉度”。我们国内真的非常不重视这个,而欧美的同行是很重视这个的,在这块做得非常好。

举个例子,我2011年曾经去瑞士日内瓦培训过一家公司,他们有个业务是专门帮瑞士本国的那些品表在新浪微博上做传播。他们的工作之一竟然是把一个微博帐号历来所有人的评论全部人肉分析一遍,用Excel全部统计好。分成正面评价和负面评价,而正面负面的评价又会分为好几个维度,具体到了是哪些角度是正面的,也有哪些维度是负面的。

而且让我吃惊的是这一切那时候竟然是人肉操作的,而操作这个的人也只学过3年中文,为了理解文字内容还要去翻词典。

社交媒体是最应该重视美誉度的。我们国内现在有了传播深度这个概念,美誉度就决定了每一层传播的时候的你的势能是加百分之几十的还是减百分之几十,按照数学公式计算,后面的结果天差地别。

今天的分享就到这里,希望对大家有启发。最后我建议大家去看一部电影叫《社交网络》,讲的是Facebook的创立历史。电影里前面十分钟在宿舍那段其实讲了马克·扎克伯格做增长黑客的方法,如果你能看懂的话非常有意思。

其实我所知道的增长黑客文化正是来源于Facebook,Facebook的历史上也有很多不能说的隐秘的获取流量的方法的。

文章来源:

用超多案例,总结了 10 个让登录体验更好的小技巧!

雪涛

看似简单的登录框,暗藏了多少值得推敲的用户体验?这10个细节,就是你和设计高手的区别。

技巧1:更明显

你不应该让你的用户到处寻找登录区域。他们找的时间越长,就会越沮丧。他们越沮丧,最终登录的可能性就越小。

一个很好的例子就是 Gmail 的登录页面。

你可以确切地知道你需要在何处登录,以及要在输入区域输入什么内容,上面的例子,如果你没有 Gmail 帐户,它允许你通过单击「创建帐户」来轻松地创建一个帐户。

好的用户体验是使你的登录区域明显,使你的用户尽可能容易地进行登录操作。

技巧2:使用第三方登录

第三方登录正迅速成为用户登录账户的方式,理由很充分。为不同的产品创建多个账户既耗时又令人困惑。很难记住一堆不同的密码和用户名。

通过允许用户使用用户的第三方账户中的信息来创建一个账户,可以解决所有关于这些问题。

让我们来看看下面的石墨文档和MONO登录时的选择方式:

甚至还有更方便的注册登录方式,手机短信验证码在注册的同时登录:

一些产品在用户点击第三方注册登录时还需要用手机号进行短信登录,从用户的角度看,这很明显是一个不好的体验,但是产品的角度去思考就不一样了,产品为了获取用户更多的信息,则需要这样来设计流程。

这种设计流程该不该用,这需要在产品和用户之间进行权衡,第三方与手机短信验证码登录,在提高用户体验的同时,可以提高用户的效率,使界面更加直观。

技巧3:更简单

因为环境不同,在中国很多网页端的网站,第三方登录很的产品很少。

例如,如果你的 QQ 没有在电脑端登录,因为即使选择第三方 QQ 登录,你也要拿出手机—打开 QQ —打开扫一扫,进行扫码登录等一些列的操作。

又或者,当你想要登录 behance,只要浏览器有记录之前的第三登录,点击第三方登录即可直接进入该网站,甚至不用注册。

可以看下面的腾讯网与 behance 的网页登录:

好的登录体验应该只有账号、密码两个输入字段,或者手机号码、短信验证码两个字段,以及使用第三方登录的选项。在简单、的同时,并为用户提供了很好的体验。

技巧4:区分注册与登录

如果一个用户来到你的网站进行注册,或者想他们返回登录界面,这就需要让用户清楚的知道他在何处,下一步应该去哪里。

我们通过使用登录字段与注册字段的区别来帮助他们,让我们看看下面的 dribbble 注册界面:

创建账户的按钮已 dribbble 的主题能很快突出在用户面前。新用户可以直接在页面上注册,而返回的用户可以使用最上面右上角的登录两字。看到上面「sign in 」字段了吗?

dribbble 使用了不同的颜色、布局去区分注册按钮与登录的入口,这样更加清晰明了。

同时可以看看 dribbble 的主页面,他们会把 sign in 与 sign up 的进行区分,在 sign up 加上微边框,让用户能更快区分两者的不同。

技巧5:跳过用户名

让用户用他们的用户名来进行登录真的不是一和很明智的做法,为用户省去记录你产品的用户名的麻烦,应该让他们使用他们的电子邮件地址或电话号码注册来进行代替用户名。

ins 让用户有机会用他们的电话号码或电子邮件地址登录。

反例:

尽可能让用户同时用手机号码或邮件地址来登录,因为用户可能会忘记他们用来登录你的产品的电子邮件地址,所以这时,用户能使用手机号码进行登录。

技巧6:密码可显示

给用户提供可显示密码的按钮,减少用户输错密码的操作,当输错的同时,可进行对错的字段进行纠正,不用全部删掉重新来。

让我们来下面的脉脉和片刻:

技巧7:记住用户信息

还有什么比再次到你之前登录的网站或 app,却发现你需要再次输入账户密码登录更令人沮丧的事情吗?

当你的用户返回到你的网站时,请确保他们已经登录了,或者为了方便登录,提前为他们预先填充账户和密码等字段。

谷歌在这方面做得很棒。每当用户需要重新登录到 YouTube、Gmail 或任何其他谷歌品牌时,他们的登录信息都会被记住,使登录过程更加简单。

盟友银行允许用户勾选 「保存用户名」 复选框,允许网站在用户到达网站时默认记住用户名。这是记住用户信息的另一个好方法,展示形式可以多样化,可根据自己产品与用户需求来进行把控。

技巧8:轻松恢复密码

有时你的用户会忘记他们的登录信息。当这种情况发生时,尽量让恢复过程尽可能的轻松。

公众号的账户密码输入栏有记住密码复选框,以防用户忘记他们的用户名和密码,不用每次进来都输入账户密码进行登录。

印象笔记对他们的密码做了一些巧妙的处理,让用户知道他们多久以前更改了密码。

这个小小的提示可以唤起用户的记忆,帮助他们记起密码。

如果用户忘记了他们的登录信息,要让他们清楚应该去哪里。如果你将使令人沮丧的情况变得不那么令人沮丧,你的用户将因此会喜欢上你的产品。

技巧9:让用户知道大写锁定已开启

我们都有过这样的经历:令人沮丧地输入和重新输入你的密码都无济于事,结果却发现你一直开着大写锁定键。

可以通过警告你的用户,防止这种情况发生。微软的 Edge 浏览器还使用户可以选择在键入时打开大写锁定时打开通知。

技巧10:无密码登录

让你的移动用户使用无密码登录,现在很多特别是金融类 app,都可以让用户进行指纹登录,因为不像其他 app 一样可以一直保持用户已登录状态,在保障安全的同时能更便捷。

以上的设计技巧与案例希望能帮助各位读者提高产品的用户体验。

欢迎关注作者的微信公众号:「设计探」

日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档