众所周知,在小程序中跳转页面的方法除了navigateTo,还有redirectTo,reLaunch,switchTab。但是这些方法都有一些限制,比如redirectTo和reLaunch不能打开tabBar页面,navigateTo和switchTab不能打开非tabBar页面。为了解决这个问题,我们需要对小程序的路由进行改造,使其能够满足我们的需求。

阅读全文 »

# history 和 hash

应用:单页面应用的 URL 导航

Hash 模式, hash 值变化不会导致浏览器向服务器发出请求,通过监听 URL 中的 hash 值(# 及其后面的部分)来实现 路由切换组件渲染

window.addEventListener(‘hashchange’, render)

History 模式利用 History API 中的 pushStatereplaceState 方法来实现 URL 的导航,无需 # 号

1
2
3
4
5
6
7
8
window.addEventListener('popstate', function (event) {
var state = event.state;
if (state.page === 'about') {
// 显示关于页面内容
} else if (state.page === 'contact') {
// 显示联系页面内容
}
});

# computed 和 watch

# router 传参

  1. query

类似 get 传参,参数会在 url? 后面拼接,刷新页面参数不会丢失

1
router.push({path: '/user', query: {id: '1'}})
  1. params

类似 post 传参,需要提前在路由中配置 path: ‘/user/:id’

1
router.push({path: name, params: {id: '1'}})

# 组件通信

  1. props 和 emit(最直接的方式)

    父传子:父组件在子组件上 v-bind 或者:绑定父组件属性,子组件内部通过 props 获取父组件

    子传父:父组件通过 v-on 或者 @监听子组件事件,子组件通过 emit 发送事件

    特别的,v-model 是一种语法糖,v-bind 和 v-on 的结合,多用于双向绑定

    父组件使用 v-model:xxx 绑定一个变量

    子组件通过 props 定义 modelXxx 变量,使用 emit (‘update:modelXxx’, value) 发送事件更新变量

    需要注意

    也可以使用 defineModel (‘xxx’) 去定义变量

  2. Provide/Inject 依赖注入(多层级透传)

    应用与子组件多层次级的透传

    父组件通过 provide 提供数据,所有子孙组件都能通过 inject 注入数据

  3. 事件总线

    适用于共同父组件的子组件之间,使用 eventBus、mitt 库

     
    1
    2
    3
    4
    5
    6
    7
    const emitter = new mitt();
    // 派发事件
    emitter.emit('event-name', data)
    // 监听事件
    emitter.on('event-name', fn);
    // 在组件卸载时移除监听,以免造成性能消耗
    onUnmounted(() => { emitter.off('event-name', onFoo) });
  4. Composition API (state)

组合式 API 提供了一种更加灵活的方式使多个组件共享逻辑和状态

1
2
3
// ComponentA
const state = reactive({ count: 0 });
export default () => { return { state } };
1
2
// ComponentB
const { state } = useState();
  1. 全局状态管理 stroe(Pinia/Vuex)

    1
    2
    3
    4
    5
    // ComponentA
    export default const store = defineStore('storeName', () => {
    count: 0,
    return { count }
    })
    1
    2
    // ComponentB
    const store = useStore();
  2. ref 实例(破坏组件封装,侵入性强,不建议使用)

子组件通过 defineExpose 暴露方法,父组件通过子组件的 ref 实例调用子组件方法

1
2
3
4
<div ref="child"></div>
<script>
defineExpose({ xxx:() => {} })
</script>
1
2
const child = ref(null);
child.value.xxx()s
  1. localStorage 和 sessionStorage

用于持久化数据存储

# HTTP 状态码

  • 1xx: 信息性状态码
  • 2xx: 成功状态码
  • 3xx: 重定向状态码
  • 4xx: 客户端错误状态码
  • 5xx: 服务器错误状态码

# 在 vue 中如何在 el 组件的基础上自定义组件,并全功能继承原有的组件方法与属性

  1. ​​属性透传​
1
2
3
<template>
<el-input v-bind="$attrs" />
</template>
  1. 事件透传
1
2
3
<template>
<el-input v-on="$listeners" />
</template>


3. 插槽透传
Vue 2​​:需区分 $slots(普通插槽)和 $scopedSlots(作用域插槽)。
​​Vue 3​​:所有插槽统一通过 $slots 处理

1
2
3
4
5
6
7
8
<template>
<el-input v-bind="$attrs">
<!-- 遍历所有插槽并渲染 -->
<template v-for="(_, slotName) in $slots" #[slotName]="scope">
<slot :name="slotName" v-bind="scope" />
</template>
</el-input>
</template>
  1. 方法透传
1
2
3
4
5
import { ref, onMounted } from 'vue';
const internalRef = ref(null);
onMounted(() => {
defineExpose({ ...internalRef.value });
});

# 全局配置样式

element-variables.scss

config-provider
el-config-provider
a-config-provider

# 权限控制

# ant-design 和 element-ui

功能支持:ant-design 开源没有虚拟列表
细节: ant-design 的日期范围组件只能从开始选到结束

# 虚拟列表

# 人脸识别

  1. 获取人脸特征、人脸比对
  2. 活体检测

# 背景

# 意义

# 权限的分类

# 后端权限

  • 从根不上讲前端仅仅只是视图层的展示,权限的核心是在于服务器中的数据变;
  • 所以后端才是权限的关键,后端权限可以控制某个用户是否能够查询数据, 是否能够修改数据等操作

# 前端权限

  • 前端权限的控制本质上来说, 就是控制端的视图层的展示和前端所发送的请求。
  • 但是只有前端权限控制没有后端权限控制是万万不可的。

# 前端权限的意义

  • 如果仅从能够修改服务器中数据库中的数据层面上讲, 确实只在后端做控制就足够了, 那为什么越来越多的项目也进行了前端权限的控制, 主要有这几方面的好处

  • 降低非法操作的可能性
    不怕赃偷就怕贼惦记, 在页面中展示出一个就算点击了也最终会失败的按钮,势必会增加有心者非法操作的可能性

  • 尽可能排除不必要清求, 减轻服务器压力
    没必要的请求,操作失败的清求,不具备权限的清求,应该压根就不需要发送,请求少了,自然也会减轻服务器的压力

  • 提高用户体验
    根据用户具备的权限为该用户展现自己权限范围内的内容,避免在界面上给用户带来困扰,让用户专注于分内之事

# 前端权限控制的设计思路

# 菜单权限

  • 在登录请求中, 会得到权限数据。前端根据权限数据, 展示对应的菜单,点击菜单才能查看相关的界面

# 按钮 / 超链接权限

  • 在某个菜单的界面中, 还得根据权限数据, 展示出可进行操作的按钮,比如删除, 修改, 增加

# 界面控制权限

  • 如果用户没有登录, 手动在地址栏敲入管理界面的地址, 则需要跳转到登录界面
  • 如果用户已经登录, 如果手动敲入非权限内的地址, 则需要跳转 404 界面

# 请求和响应的控制

  • 如果用户通过非常规操作, 比如通过浏览器调试工具将某些禁用的按钮变成启用状态, 此时发的请求, 也应该被前端所拦截

# 前端权限控制的实现

# 权限菜单栏控制

  • 用户登录之后服务端返回一个数据,这个数据有菜单列表和 token,我们把这个数据放入到 vuex 中,然后主页根据 vuex 中的数据进行菜单列表的渲染
    问题: 刷新界面 vuex 数据消失,菜单栏消失
    解决: 将数据存储在 sessionStorage 中,并让其和 vuex 中的数据保持同步

# 界面的控制

  • 路由导航守卫
  • 动态路由

# 浏览器兼容性

1
面试官:说说你在工作中是怎么处理浏览器兼容性
  • 这个问题,是面试官想知道你的学习广度,你的知识体系是否全面。
  • 其实针对前端三部分(HTML、CSS、JavaScript),考虑浏览器兼容性只有 CSS 和 JavaScript;因为针对 HTML,在开发中就常用的几个标签,浏览器从头到脚都认识,还需要兼容吗?
  • 针对 CSS 的兼容性,你只需要有添加浏览器前缀变量转换等意识即可
  • 针对 JavaScript 的兼容性,你只需要有新旧语法兼容新旧函数兼容意识即可。
  • 只需要有这两个意识就行,实现也已经不需要从头到尾的写,而是借助工具即可

# CSS 兼容性

# 浏览器前缀

  • 浏览器前缀是浏览器厂商为了实验性 CSS 属性而添加的标识符,它们通常用于 CSS 规则的前面。以下是一些常见的浏览器前缀:
  1. webkit-:用于 Chrome、Safari(WebKit 内核)
  2. moz-:用于 Firefox(Gecko 内核)
  3. o-:用于 Opera(Presto 内核,已逐渐淘汰)
  4. ms-:用于 Internet Explorer(Trident 内核)
  • 例如,如果你想要使用 CSS 的 transform 属性,可能需要添加所有浏览器的前缀:
1
2
3
4
5
6
7
.element {
-webkit-transform: rotate(45deg); /* Chrome, Safari */
-moz-transform: rotate(45deg); /* Firefox */
-ms-transform: rotate(45deg); /* IE */
-o-transform: rotate(45deg); /* Opera */
transform: rotate(45deg); /* 标准语法 */
}
  • 为了简化这个过程,可以使用一些工具自动添加浏览器前缀:
  1. Autoprefixer:一个后处理工具,可以根据 Can I Use 的数据自动添加所需的浏览器前缀。
  2. PostCSS:一个使用 JavaScript 的插件系统,可以处理 CSS 的转换,包括添加前缀。

# 变量转换

  • CSS 变量的兼容性问题较少,因为它们已经成为 CSS 的一个标准部分。
  • 但是,为了确保在不支持 CSS 变量的旧浏览器中也能正常显示,可以使用以下方法:
  1. 回退值:在 var () 函数中提供回退值。
  2. PostCSS:使用 PostCSS 插件将 CSS 变量转换为静态值。

# JavaScript 的兼容性

  • 再来说说 JavaScript 的兼容性吧,针对新旧语法的兼容可以作转换,而针对新旧函数的兼容就需要加补丁。

# babel

  • 其实在开发过程中,最常见的就是跟 JavaScript 打交道,也会真实感受到 JavaScript 存在新的语法,那么这些新的语法就需要转化,才能被浏览器认识。那么这时候就可以借助一个工具 babel。用于专门来降低 JavaScript 语法的。
  • babel 就是一个编译器,把一段源代码转化成另外一段新代码,新代码就能被浏览器识别。对了,既然 babel 是工具(postcss 也是一样),能单独使用,也能够配合使用。而我们在项目开发过程中,都会使用构建工具(比如说 webpack),但是又想使用 babel 工具,那么这时候就需要一个桥梁,而 webpack 中的桥梁就是 babel-loader,具体怎么操作你回去研究一下。

# polyfill

  • 手动打补丁

  • 根据覆盖率自动打补丁

  • 根据浏览器特性,动态打补丁

  • JS 代码能够被转化减低,适配了市场占比的浏览器,是不是就已经完成了呢?当然没有。
    在 ES6 中出现了 Promise,fetch,以及数组和字符串新的方法,babel 会进行转化吗?会转化成什么呢?肯定不会被转化撒,因为它们都是函数调用,对于 babel 来说就是一个普通的函数调用,只是找不到函数的实现体而已,只是会报错而已。

  • 那么这里也就需要兼容一下,因为新版本的浏览器是认识的,老版本的浏览器是不认识的,那么这里就需要为了兼容了老版浏览器,新部署一个 JS 文件(类似补丁),里面存放了各个函数(promise, fetch)体的实现代码。然后浏览器就能够正常的识别了。

# 参考文章

掘金 - 面试官:说说你在工作中是怎么处理浏览器兼容性

0%