分类
svg

APP与H5互相调用方案

APP调用H5

/**
 * 这里注入一些全局方法供app端使用
 */
export function injectGlobalProps(name: string | Record<string, any>, callback?: Function) {
  // if (isApp() || __MODE__ === 'start') {
  if (!window.INVITATION_CARD) {
    window.INVITATION_CARD = {}
  }
  if (isString(name)) {
    window.INVITATION_CARD[name] = callback
  } else if (isPlainObj(name)) {
    Object.keys(name).forEach((key) => {
      window.INVITATION_CARD[key] = name[key]
    })
  }
  // }
}

H5调用APP

/**
 * 调用app端注入的方法
 * onEditElement(element: 元素数据) 编辑元素 点击元素,将元素数据传过app
 * onEditImage({ element: ImageElement, allImageElements: ImageElement[] }) 编辑图片 allImageElements 当前请帖所有图片数据
 */
export function callAppBridge(name: string, params?: any) {
  try {
    if (name) {
      console.log(name, params)
      if (isAndroid() && window.messageHandlers && window.messageHandlers[name]) {
        window.messageHandlers[name](JSON.stringify(params))
      } else if (window.webkit?.messageHandlers?.[name]) {
        window.webkit.messageHandlers[name].postMessage(params)
      } else {
        console.log('不存在的方法' + name)
      }
    }
  } catch (e) {
    console.log(e)
  }
}

需要APP提前将方法写入的messageHandlers中

分类
svg

无耦合弹窗(Vue)

在body中挂载一个组件

import Vue from 'vue'

/**
 * 创建一个根组件
 * @param Component 组件
 * @param props 组件属性
 */
const createComponent = (Component, props) => {
  // vue.extend()获取创建实例
  const Ctor = Vue.extend(Component)
  // 创建组件实例,这时得到的是虚拟dom,如何转化为真实dom
  const comp = new Ctor({
    options: {}
  })
  // 前面说到$mount就是这个作用
  comp.$mount()
  // 挂在在body上,这时是comp的dom
  document.body.appendChild(comp.$el)
  comp.remove = () => {
    // 移除本身
    document.body.removeChild(comp.$el)
    // 释放自己所占资源
    comp.$destroy()
  }
  return comp
}

export default createComponent

创建弹窗实例

import Info from './Info'
import createComponent from './createComponent'

/**
 * 喜糖弹窗组件
 */
const Modal = {}

// 弹窗组件实例
const modalInstance = {}
const openModal = (name, Component, options) => {
  if (!modalInstance[name]) {
    modalInstance[name] = createComponent(Component)
  }
  // 在渲染完成打开,否则首次动画播放有问题
  setTimeout(() => {
    modalInstance[name].open(options)
  })
}
// 弹窗预加载 (可在项目入口调用该函数,实现弹窗预加载)
Modal.prefetch = () => {
  modalInstance.info = createComponent(Info)
}
/**
 * 信息弹窗
 *  {
 *    title?: String // 弹窗标题
 *    content?: String // 弹窗内容
 *    onOk?: () => void  // 确认点击回调
 *    okText?: String // ok按钮文本。 默认: 确认
 *    cancelText?: String // cancel按钮文本 默认: 取消
 *    containerTracker: 弹窗容器tracker(可用于弹窗曝光) 支持传递v-tracker埋点数据
 *    okTracker: 确认按钮tracker (可用于确认按钮点击埋点) 支持传递v-tracker埋点数据
 *  }
 * @param options
 */
Modal.info = (options = {}) => {
  openModal('info', Info, options)
}
export default Modal

onOk函数如何实现

data() {
    return {
      isShow: false,
      options: { title: '', content: '', onOK: () => {}, onCancel: () => {} },
    }
  },
  methods: {
    // 调用show方法展示
    open(options) {
      this.options = { ...this.options, ...options }
      this.isShow = true
    },
    handleOkClick() {
      this.options.onOK()
      this.isShow = false
    },
    // 消失后移除自身所占资源
    hide() {
      this.isShow = false
      this.options.onCancel()
    },
  },

如何使用

Modal.info({
            title: 'xxxxx:',
            okText: '我知道了',
            content:
              'xxxx',
            onOK: () => {
              
            },
            
          })
分类
svg

自定义list-style

list-style是使用在ul标签,和ol标签中,通常我们会让list-style的值为none,但其实我们也可以自定义list-style的样式和规则,只是使用场景有限。而且它的同行有选择器,couter-reset等,因此是一个不常使用的技术。(不想讲了)

@couter-style

制订一个自定义计数规则

 @counter-style triangle {
        ...
      }
      ul {
        list-style: triangle;
      }

couter-style下的三个属性

suffix

后缀,suffix:’ >’; 相当于把原有的’ .’替换了

symbols

符号,如果是原来默认的ol计数则它的符号是

symbols: ‘0’ ‘1’ ‘2’ ‘3’ ‘4’ ‘5’ ‘6’ ‘7’ ‘8’ ‘9’

system

计数规则

system: cyclic

循环计数

system: fixed

如果是有序计数,则只计数前有符号的,其余的按常规的有序计数来

system: numeric

默认的有序计数规则

system: additive

相加规则,比较有趣

@counter-style triangle {
        system: additive;
        additive-symbols: 6 ⚅, 5 ⚄, 4 ⚃, 3 ⚂, 2 ⚁, 1 ⚀;
        suffix: ' ';
      }
image - 自定义list-style
分类
svg

css语法解析系列~animation

animation: <single-animation>#

single-animation

single-animation=<time> || <easing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state> || [none | <keyframes-name>]

single-animation-direction

single-animation-direction = normal | reverse | alternate | alternate-reverse

normal:默认值正常顺序

reverse:动画按相反的方向播放

alternate:奇数动画按顺序播放,偶数动画按相反的方向播放

alternate-reverse:奇数动画按相反方向播放,偶数动画按顺序播放

single-animation-fill-mode

single-animation-fill-mode= none | forwards | backwards | both

none: 默认值,播放完后就当没有动画

forwards:播放完后元素处于最后一帧状态

backwards:播放前动画处于第一帧的状态

both:播放前处于第一帧,播放后处于最后一帧

single-animation-play-state

single-animation-play-state=running | paused

running:正常播放动画

paused:动画暂停

分类
svg

CSS语法解析系列~font

font

font = [[<font-style> || <font-variant-css2> || <font-stretch-css3>? <font-size> [ / <line-height>]? <font-family> ]? | caption | icon |menu | message-box | small-caption | status-bar

<font-style>

它的默认值是normal

font-style = normal | italic | oblique <angle>?

如果使用简写,那么它必须要有font-family不然是无效的

oblique后面的<angle>如果使用大概率无效

<font-family>

font-family = [<family-name> | <generic-family>]#

<family-name>

通用字体名称

<font-variant-css2>

font-variant-css2 = [normal | small-caps]

small-caps是小型大写字母的意思

涉及的属性名有font-synthesis-weight,font-synthesis-style,font-synthesis-small-caps,font-synthesis

<font-stretch-css3>

允许你使文字变宽或者变窄

font-stretch-css3 = [normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded ]

属性名是 font-stretch,下面的属性值很可能没有卵用

ultra-condensed:使文本窄的不能再窄,大概率无效果

extra-condensed:紧缩程度第二大的字体

condensed:紧缩程度第三大的字体

semi-condensed:紧缩程度最小的字体

normal:默认值

semi-expanded:使文本稍微变窄

expanded:变得更宽

extra-expanded:变得最宽

<font-size>

font-size = <absolute-size> | <relative-size> | <length-percentage> | math

默认值为absolute-size的medium

<absolute-size> = [xx-small | x-small | small | medium | large | x-large | xx-large]

这些值的大小由用户控制

<relative-size> = [larger | smaller]

<font-weight>

font-weight = normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900

默认值:normal

caption

表格头

icon

图标字体,大小16px,会使英文紧凑一点,font-weight大一点

menu

使用系统字体,可以给用户一种熟悉的感觉

message-box

dialog中使用的字体

small-caption

小标题

status-bar

windows电脑的状态栏

分类
svg

React代码CodeReview

[].slice.call转换为Array.from

组件中调用函数不正确导致多次渲染

// bad

image - React代码CodeReview

// good store为mobx

image 1 - React代码CodeReview
image 2 - React代码CodeReview

useEffect使用定时器没有返回清除定时器

jsx内不要定义临时函数,可以用useCallback

// bad

image 4 - React代码CodeReview

// good

image 5 - React代码CodeReview

jsx内不要定义临时对象,可以用useMemo

// bad

image 6 - React代码CodeReview

// good

image 7 - React代码CodeReview
分类
svg

移动端调试工具

light proxy

https://lightproxy.org/doc/getting-started

  1. 打开light-proxy
  2. 手机扫手机代理,下载证书
  3. 手机信任证书
  4. 手机wifi配置代理
  5. light-proxy配置代理规则

xcode

分类
svg

Webpack Plugins 构造组件库使用的API

webpack-node-externals

const nodeExternals = require('webpack-node-externals');
...
module.exports = {
    ...
    target: 'node', // in order to ignore built-in modules like path, fs, etc.
    externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
    ...
};

组件库内不包含node_modules,减少组件体积

VueLoaderPlugin

const VueLoaderPlugin = require('vue-loader/lib/plugin');
 module: {
    rules: [
      {
        test: /\.(jsx?|babel|es6)$/,
        include: process.cwd(),
        exclude: config.jsexclude,
        loader: 'babel-loader'
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          compilerOptions: {
            preserveWhitespace: false
          }
        }
      }
    ]
  },
  plugins: [
    new ProgressBarPlugin(),
    new VueLoaderPlugin()
  ]

没有使用vue-cli创建项目时又要用到vue需要此plugin

terser-webpack-plugin

const TerserPlugin = require('terser-webpack-plugin');
optimization: {
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          output: {
            comments: false
          }
        }
      })
    ]
  },

压缩js代码并去掉注释

分类
svg

svg sprite

给svg文件一个名字,方便vue使用svg

文件存放地址

src->assets->svg-icons

qi ye wei xin jie tu 16104356734716 - svg sprite

在项目中引入文件

src->assets->svg-icons->index.js

const requireAll = requireContext => requireContext.keys().map(requireContext);
const req = require.context('./icons', false, /\.svg$/);
requireAll(req);
export default req;

main.js

import '@/assets/svg-icons';

对引入的svg文件进行配置

vue.config.js

function resolve(dir) {
  return path.join(__dirname, dir);
}
const vueConfig = {
  chainWebpack: (config) => {
    // svg
    const svgRule = config.module.rule('svg');
    svgRule.uses.clear();
    svgRule.include
      .add(resolve('src/assets/svg-icons/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'e2-[name]',
      })
      .end();
};
module.exports = vueConfig;

做一个svg组件然后引用

<template>
  <svg aria-hidden="true"
    class="svg-icon">
    <use :xlink:href="icon"></use>
  </svg>
</template>

<script>
export default {
  name: 'e2-svg',
  props: {
    name: {
      type: String,
      required: true,
    },
  },
  computed: {
    icon() {
      return `#e2-icon_${this.name}`;
    },
  },
};
</script>
<style scoped>
  .svg-icon{
    width:1em;
    height:1em;
    vertical-align:-.09em;
    margin-right:.2em;
  }
</style>

如何使用

<e2-svg name="burse"></e2-svg>

注意事项:name不是icon_burse,因为经过webpack处理,svg文件暴露除了id=“e2-icon_burse”,组件上用的是e2-icon_${this.name},所以name=“burse”