分类
react

React mobx Store 分拆

一个较大的项目如果所有内容都写在一个store里,就显得太多。将一个store拆散,分为一个主store和多个副store。副store可以用到主store的数据。主store有副store的引用便于提供React.createContext。和保持只有一个Provider包裹在主UI组件中

创建主Store

// store.ts
import PageEffectStore from '../Home/stores/PageEffectStore'
import HybridStore from './stores/HybridStore'

class Store {
  /** 副store1 */
  pageEffectStore: PageEffectStore
  /** 副store2 */
  hybridStore: HybridStore
  pageData = ''
  constructor() {
    this.hybridStore = new HybridStore({ mainStore: this })
    this.pageEffectStore = new PageEffectStore({ mainStore: this })
    makeAutoObservable(this)
  }
}

创建副Store

// hybridStore
interface HybridStoreConstructor {
  mainStore: MainStore
}

class HybridStore {
  mainStore: MainStore
  constructor({ mainStore }: HybridStoreConstructor) {
    this.mainStore = mainStore
    makeAutoObservable(this)
  }
}
分类
react

React mobx共享全局变量

mobx持久性变量实现方式。会有一下几个步骤:1.定义store。2.暴露store。3.引入在.tsx引入store。4.在.tsx内使用store

定义Store

// store.ts
import { makeAutoObservable } from 'mobx'

class Store {
  visible = false
  constructor() {
    makeAutoObservable(this)
  }
}

export default Store

暴露Store

// context.ts
import React from 'react'
import Store from './store'

const GlobalContext = React.createContext<Store>(new Store())

export default GlobalContext

引入Store

// index.tsx
import React, { FC } from 'react'
import Store from './store'
import GlobalContext from './context'
import { observer, useLocalObservable } from 'mobx-react'

const Home:FC = () => {
  const store = useLocalObservable(() => new Store())
  return (<GlobalContext.Provider value={store}>...</GlobalContext.Provider>)
}

export default observer(Home)

使用Store

import GlobalContext from '../context'
import React, { FC, useContext } from 'react'

const LongPage:FC<...> = () => {
  const globalStore = useContext(GlobalContext)
}
export default observer(LongPage)

分类
CSS

对层叠上下文内部显示顺序的理解

这篇文章不讲述层叠上下文之间的显示顺序,而是探究在一个父层叠上下文上,子元素的显示顺序(子元素不会产生新的层叠上下文)。相同的显示等级需要考虑先来后到原则。因此本次只考虑不同的显示等级,以背景色的方式。查看覆盖情况得出显示等级。

第一等

position为非static

第二等

display:inline/inline-block

flex容器的子项

第三等

float:left/right

第四等

display:block

冲突情况

当display:inline-block和float:left/right同时存在时,显示等级为第三等,是由于inline-block失效造成的。

父元素与子元素等级不同时的显示顺序

第一个:父元素第一等,子元素第四等。第二个父元素第四等,子元素第一等

第二个的子元素显示在第一个的子元素上方。

第一个:父元素第二等,子元素第四等。第二个父元素第四等,子元素第一等

第二个的子元素显示在第一个的子元素上方

第一个:父元素第二等,子元素第四等。第二个父元素第四等,子元素第三等

第一个的子元素显示在第二个的子元素上方

第一个:父元素第四等,子元素第一等。第二个父元素第一等,子元素第四等。

第二个的子元素显示在第二个子元素的上方

结论:子元素的显示等级由子元素本身和父元素的显示等级决定,如果子元素的显示等级比父元素的显示等级高,则子元素的显示等级为自身的显示等级,如果子元素的显示等级比父元素的显示等级低,则子元素的显示等级为该层叠上下文下,等级最高的父元素的显示等级。

分类
javascript regex 常识

用户环境判断

在开发过程中,我们可能会针对不同的环境做不同的跳转等操作,因此判断环境也是一个比较必要的技术。

const matchEquipment = reg => reg.test(window.navigator.userAgent)

export const isAndroid = () => matchEquipment(/Android/i)

export const isIOS = () => matchEquipment(/ip(hone|od|ad)/i)

// 企业微信
export const isWorkWeiXin = () => matchEquipment(/wxwork/i)

export const isWeiXin = () => matchEquipment(/MicroMessenger/i)

export const isQQ = () => matchEquipment(/QQ/i)

export const isWeiBo = () => matchEquipment(/WeiBo/i)

export const isWindows = () => matchEquipment(/IEMobile/i)

export const isMobile = () => matchEquipment(/Android|webOS|iPhone|iPod|BlackBerry/i)

export const isWeiXinMiniPrograme = () => return matchEquipment(/miniProgram/i)
分类
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: () => {
              
            },
            
          })