苍溪网站建设制作,如何在网站搜关键字,wordpress 取消赞,查域名注册人vue生命周期#xff08; 组件从创建到销毁的过程就是它的生命周期#xff09;
创建前 beforeCreat#xff08; 在这个阶段属性和方法都不能使用#xff09;
创建时 created#xff08; 这里时实例创建完成之后#xff0c; 在这里完成了数据监测#xff0c; 可以使用数…vue生命周期 组件从创建到销毁的过程就是它的生命周期
创建前 beforeCreat 在这个阶段属性和方法都不能使用
创建时 created 这里时实例创建完成之后 在这里完成了数据监测 可以使用数据 修改数据 不会触发updated 也不会更新视图
挂载前 beforeMount 完成了模板的编译 虚拟DOM也完成创建 即将渲染 修改数据 不会触发updated
挂载时 Mounted 把编译好的模板挂载到页面 这里可以发送异步请求也可以访问DOM节点
更新前 beforeUpdate 组件数据更新之前使用 数据是新的 页面上的数据时旧的 组件即将更新 准备渲染 可以改数据
更新时 updated render重新做了渲染 这时数据和页面都是新的 避免在此更新数据
销毁前 beforeDestroy 实例销毁前 在这里实例还可以用 可以清除定时器等等
销毁时 destroyed 组件已经被销毁了 全部都销毁
keep-alive 组件缓存 不销毁 刷新的时候 保存状态
多了两个生命周期 activited 组件激活时 deactivited 组件没被激活时缓存组件 避免组件内数据重复渲染 直接可以在页面中调用。
优点 组件切换过程中 组件保存在内存中 防止重复渲染 减少加载时间 提高性能。
created和mounted
created 在渲染前调用 通常先初始化属性 然后做渲染
mounted 在模板渲染完成后 一般都是初始化页面后 在对元素节点进行操作在这里请求数据可能会出现闪屏的问题 created里不会
请求的数据对DOM有影响 那么使用created 如果请求的数据对DOM无关 可以放在mounted
vue中的修饰符
1. 事件修饰符
.stop 阻止冒泡 .prevent 组织默认行为 .once 事件只会触发一次
2. 按键修饰符
.keyup 键盘抬起 .keydown 键盘按下
3. 鼠标修饰符
.left 鼠标左键 .right 鼠标右键 .middle 鼠标中键
4. 表单修饰符
.lazy 等输入完之后再显示 .trim 删除内容前后的空格 .number 输入是数字或转为数字
VUE组件
组件通信
父组件通过 props 传值给子组件子组件通过 $emit 传值给父组件或触发父组件事件
父组件 $refs 获取子组件 值或方法子组件 $parent 获取父组件值或方法。 如果是多重嵌套 也可以使用多层。
祖先组件通过 provide 传值给 孙子组件通过 inject 接受。允许一个祖先组件向其所有子孙后代注入一个依赖 不论组件层次有多深 并在其上下游关系成立的时间里始终生效。 注意 provide 和 inject 绑定并不是可响应的
attrs 实现孙子组件获取祖先组件的 attribute 绑定的值(class和style除外)listeners 则包含了 祖先组件 中(不含.native 修饰器的) v - on 事件监听器
注意孙子组件无法直接向祖先组件传值需要通过父组件或者使用事件总线本地存储等进行通信
兄弟组件通信兄传父 父传弟 反之亦然。 太繁琐
安装引用 插件 mitt 或者 插件 $bus 两者都是基于 事件总线event - bus
父子组件生命周期钩子函数执行顺序
创建: 父beforeCreate - 父created - 父beforeMount - 子beforeCreate - 子created - 子beforeMount - 子mounted - 父mounted
销毁: 父beforeDestroy - 子beforeDestroy - 子destroyed - 父destroyed
VUE的单项数据流
Vue 的单向数据流是指数据在 Vue 应用中的流动方向是单向的数据总是从父组件传到子组件子组件没有权利修改父组件传过来的数据只能请求父组件对原始数据进行修改。这样会防止从子组件意外改变父组件的状态。
defineProps 父传子用在子组件接收父组件的传值用来声明props
defineEmits 子传父用在子组件将子组件的方法传递给父组件用来声明emits
defineExpose 子传父用在子组件暴露想传递的值或方法父组件通过ref属性获取子组件暴露的
Suspense
templatediv classapph3我是App组件/h3Suspensetemplate v-slot:defaultChild //templatetemplate v-slot:fallbackh3稍等加载中.../h3/template/Suspense/div
/template
// import Child from ./components/Child//静态引入
import { defineAsyncComponent } from vue;
const Child defineAsyncComponent(() import(./components/Child)); //异步引入
export default {name: App,components: { Child },
};
在上面的例子中AsyncComponent 被定义为异步组件它只有在被实际渲染到页面时才会从 ./AsyncComponent.vue文件中加载和解析而不是在页面加载时就被引入。通过 defineAsyncComponentVue3 提供了一种简单而强大的方式来管理和优化组件的加载行为使得应用程序可以更高效地使用和分发组件资源
Vuex页面刷新数据丢失解决方法
需要做 vuex 数据持久化 一般使 用本地储存的方案 来保存数据可以自己设计存储方案也可以使用第三方插件。
推荐使用 vuex-persist(脯肉赛斯特 )插件它是为 Vuex 持久化储存而生的一个插件。不需要你手动存取 storage 而是直接将状态保存至 cookie 或者localStorage 中
vue路由的hash模式和history模式区别
1. hash的路由地址上有 #号 history模式没有
2. hash模式支持低版本浏览器 history不支持 因为是H5新增的API
3. hash模式利用的是锚点 history借助 history 对象中的 pushState() 函数重写 URL 路径 都是通过控制页面的display none 属性
4. hash模式简单部署容易不需要服务器端的配置。history需要
5. hash不会重新加载页面在做回车刷新的时候 hash模式会加载对应页面。history会报错404
vue-router
路由传参方式
router 传值方式router-link 和 this.$router.push
1 query 传参显示参数 this.$router.push({ name: Child, query: { id: 123 } })
2 params 传参显示参数和不显示参数
显示参数 this.$router.push({path:/child/${id},})
不显示参数 this.$router.push({ name: Child, params:{ id: 123 } })
三种导航守卫
1. 全局守卫Global Before Guards 写在 router/index.js 文件中的全局
用于全局的路由控制逻辑如登录验证、权限控制等。
2. 路由守卫Per-Route Guards 写在 router/index.js 文件中的const routes [] 中的每一个路由内
用于特定路由或路由群组的控制逻辑如权限验证、数据预加载等。
3. 组件守卫In-Component Guards写在该组件的Vue页面中类似 生命周期的写法
用于处理单个组件在路由导航过程中的逻辑如特定路由下的数据加载、页面交互等。
to目标路由对象from即将要离开的路由对象 next它是最重要的一个参数调用该方法后才能进入下一个钩子函数。
next()//直接进to 所指路由
next(false) //中断当前路由
路由拦截
路由拦截 需要在路由配置中添加一个字段 它是用于判断路由是否需要拦截然后再在全局或路由守卫进行拦截
{name: index,path: /index,component: Index,meta: {requirtAuth: true}
}
router.beforeEach((to, from, next) {if (to.meta.requirtAuth) {next()}
})
AXIOS的封装和拦截
import axios from axios
import getBaseUrl from ./getBaseUrl
// 创建axios实例
const request axios.create({baseURL: getBaseUrl(),// 所有的请求地址前缀部分(没有后端请求不用写)timeout: 80000, // 请求超时时间(毫秒)
})
// request拦截器
request.interceptors.request.use(config {// 如果你要去localStor获取token,(如果你有)// let token localStorage.getItem(x-auth-token);// if (token) {//添加请求头//config.headers[Authorization]Bearer token// }return config},error {// 对请求错误做些什么Promise.reject(error)}
)
// response 拦截器
request.interceptors.response.use(response {// 对响应数据做点什么return response.data},error {// 对响应错误做点什么//响应错误let message ;if (error.response error.response.status) {const status error.response.status;switch (status) {case 401:message 未授权;break;case 404:message 请求地址出错;break;case 500:message 服务器内部错误!;break;default:message 请求失败;}return Promise.reject(error);}return Promise.reject(error);
}
)
export default request
vue 强制刷新
1. localtion.reload() // 跟按F5一样 不会利用缓存直接重新加载 浪费性能
2. this.$router.go(0) // 跟按F5一样 不会利用缓存直接重新加载 浪费性能
3. 找个空白页过渡一下 // 地址闪动效果页面闪动
4. 利用 provider inject 在孙组件中就可以直接调用祖先组件的方法 进行刷新页面 推荐
其本质上是通过控制 app.vue 中 router-view 标签设置 v-ifshow 控制他先消失再显示
因为是 刷新按钮 一般不在 app.vue 文件而是在其子孙组件中所以使用到 provider 和 inject
computed和watch
1. computed是计算属性data中无定义的数据computed的值可以直接使用watch是监听 监听的是data中数据的变化
2. computed是支持缓存 依赖的属性值发生变化 计算属性才会重新计算 否则用缓存 watch不支持缓存
3. computed不支持异步 watch是可以异步操作
4. computed是第一次加载就监听 watch不监听 有 deep: true // 开启深度侦听immediate: true // 立马监听
5. computed函数中必须有return watch不用
watch和watchEffect
1 watchEffect是立即执行的在页面加载时会主动执行一次来收集依赖而watch是惰性地执行。
2 watchEffect只需要传递一个回调函数watch至少要有两个参数第三个参数是配置项第一个参数是侦听的数据第二个参数是回调函数。
3 watchEffect获取不到更改前的值而watch可以同时获取更改前和更改后的值。
4 watchEffect自动追踪所有使用的响应式数据当任何相关数据变化时重新运行整个函数watch 用于监测一个或多个特定的响应式数据源并在变化时执行回调。
vue过滤器
vue的特性 用来对文本进行格式化处理。 使用它的两个地方 一个是插值表达式 一个是v-bind
1. 全局过滤器Vue.filter(add, function(v) {return v 10 ? 0 v : v
})
{{33 | add}}
2. 本地过滤器 和methods同级filter: {add: function(v) {return v 10 ? 0 v : v}
}
插槽Slot
1. 占位符 2. slot 名称位置 template 3. 子组件传值 v-slot slotProps
Vue 中 delete 和 Vue.delete 删除数组
delete 只是被删除的元素变成了empty/undefined 其他的元素的键值还是不变。Vue.delete 直接删除了数组 改变了数组的键值 。
let arr [1, 2, 3];
delete arr[1];
console.log(arr); // 输出[1, undefined, 3]
let arr [1, 2, 3];
vue.$delete(arr, 1);
console.log(arr); // 输出[1, 3]
内置指令和自定义指令
v-model的双向绑定原理
v-model 是一个语法糖结合了 v-bind 和 v-on 两个指令的功能。v-bind用于将表单控件的值绑定到 Vue 实例的数据属性上。v-on用于监听表单控件的输入事件然后将事件的新值更新到 Vue 实例的数据属性上。
v-html、 v-bind、 v-on、 v-model......
// 自定义指令
Vue.directive(focus, {inserted: function(el) {el.focus()}
})
开发过自定义指令 拖拽复制长按防抖节流过滤日期。
vue2 $set 和 $nextTick
只有vue2 有 $set 方法用于向响应式对象添加响应式属性并确保这个新添加的属性是响应式的。Vue.js在初始化实例时会将data中的属性转换为getter/setter从而使其变成响应式的。但是对于新增的属性Vue无法自动实现响应式因此需要使用$set方法来手动添加响应式属性。
$nextTick方法主要用于确保在DOM更新完成后执行特定的回调函数。
VueX(Vue2) 和 Pinia(Vue3)
VueX state 存储变量 getters state的计算属性 mutations 提交更新数据的方法 actions 和 mutations 差不多 他是提交mutations来修改数据 可以包括异步操作
Piniastate 存储变量 getters state的计算属性 actions(包含 mutations)
hooks详解
Vue3 Hooks是一种函数式的API允许我们在组件之间复用状态逻辑。这些函数包括setup、reactive、ref等以及一系列生命周期函数如onMounted、onUpdated等。
// 1 获取宽高hooks可以变成获取不同设备的hooks
// hooks/xxx.js
import{ ref, onMounted, onUnmounted } from vue
export function useWindowResize(){const width ref(window.innerWidth);const height ref(window.innerHeight);const handleResize(){width.value window.innerWidth;height.value window.innerHeight;}onMounted(() { window.addEventListener(resizehandleResize)});onUnmounted(() {window.removeEventListener(resizehandleResize)});return { width, height }
}
// 使用就更简单了只需要调用这个钩子就可以获得 window 的宽度和高度。
// xxx.vue
import useWindowResize from ../hooks/xxx
const { width, height } useWindowResize()// 2 剪切hooks
// hooks/xxx.js
function copyToClipboard(text){// 这个 input 最好变成参数传递进来 id 或者 class 名let input document.createElement(input);input.setAttribute(valuetext);document.body.appendchild(input);input.select();let result document.execCommand(copy);document.body.removechild(input);return result;
}
export const useCopyToclipboard(){return(text){if(typeof text string || typeof text number){return copyToClipboard(text);}return false;}
}
// 使用xxx.vue
const copyToClipboard useCopyToclipboard()
copyToClipboard(just copy)
// 3 滚动条滚动到底部hooks
import { onMountedonUnmounted } from vue
export const useScrollToBottom (callback () {}) {const handleScrolling () {if((window.innerHeight window.scrollY) document.body.scrollHeight){callback()}}onMounted(() {window.addEventListener(scrollhandleScrolling)});onUnmounted(() {window.removeEventListener(scrollhandleScrolling)});
}
// 使用xxx.vue
useScrollToBottom(() {console.log(到底了)
})
hooks 和 units 区别
1. 表现形式不同 hooks 是在 utils 的基础上再包一层组件级别的东西(钩子函数等) utils 一般用于封装相应的逻辑函数 没有组件的东西
2. 数据是否具有响应式 hooks 中如果涉及到 ref reactive computed 这些 api 的数据 是具有响应式的 而 utils 只是单纯提取公共方法就不具备响应式
3. 作用范围不同 hooks 封装 可以将组件的状态和生命周期方法提取出来 并在多个组件之间共享和重用 utils 通常是指一些辅助函数或工具方法 用于实现一些常见的操作或提供特定功能。
v-if v-show v-for
v-if和v-show的区别都可以控制元素的显示和隐藏
1. v-show时控制元素的display值来让元素显示和隐藏 v-if显示隐藏时把DOM元素整个添加和删除
2. v-if有一个局部编译 / 卸载的过程 切换这个过程中会适当的销毁和重建内部的事件监听和子组件 v-show只是简单的css切换
3. v-if的切换效率比较低 v-show的效率比较高
[Vue] 中为何不要把 v-if 和 v-for 同时⽤在同一个元素上
1 优先级冲突 v-for 指令在 Vue 中的优先级比 v-if 高。这意味着如果你在一个元素上同时使用 v-if 和 v-forv-for 将首先运行并渲染列表中的所有项目然后 v-if 将根据条件决定是否显示整个列表。这可能会导致不必要的渲染和性能问题。
2 性能问题 当 v-if 的条件不满足时Vue 仍然会对列表中的每个项目执行 v-for即使这些项目最终不会被渲染到 DOM 中。这种额外的计算和虚拟 DOM 的更新可能会影响性能特别是当列表中的项目数量较大时。
在vue2中v-for的优先级高于v-if; 在vue3中v-if的优先级高于v-for. 外层使用另外的div或template嵌套
Vue2 的实现原理
vue.is 是采用数据劫持结合发布者-订阅者模式的方式通过 Object.defineProperty()来劫持各个属性的 settergetter在数据变动时发布消息给订阅者触发相应的监听回调。
具体步骤
第一步:需要 observe 的数据对象进行递归遍历包括子属性对象的属性都加上setter和 getter这样的话给这个对象的某个值赋值就会触发 setter那么就能监听到了数据变化
第二步:compile 解析模板指令将模板中的变量替换成数据然后初始化渲染页面视图并将每个指令对应的节点绑定更新函数添加监听数据的订阅者一旦数据有变动收到通知更新视图
第三步:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁
第四步:MVVM 作为数据绑定的入口整合 Observer、Compile 和 Watcher 三者通过Observer来监听自己的 model数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher搭起 Observer和 Compile 之间的通信桥梁达到数据变化 -视图更新;视图交互变化(input)- 数据 model 变更的双向绑定效果。
Model模型 View视图 ViewModel视图模型
vue3 proxy
一、defineProperty 是对属性进行劫持proxy是代理整个对象
二、defineProperty 无法监听对象新增属性Proxy可以所以vue2用到了 $set
三、defineProperty 无法监听对象删除属性Proxy可以
四、defineProperty 无法监听数组下标改变值的变化proxy 可以且不需要对数组的方法进行重写 vue2和vue3已实现数据响应式来更新DOM了为什么还有diff算法
1 性能优化:直接操作真实 DOM 是非常昂贵的而虚拟DOM 可以在内存中快速进行比较和计算差异。Diff算法帮助减少了更新操作的次数和范围从而提升了页面渲染的性能。
2 批量更新:Diff算法能够将多次 DOM 更新操作合并为一次避免了频繁的 DOM 操作减少了浏览器的重排和重绘。
3 Diff算法可以智能地比较新旧DOM树的变化只更新必要的部分从而提高了更新效率。 vue2 和 vue3 的区别
1.双向数据绑定的原理不同
2.生命周期的不同
3.组件、指令和插槽使用方式都不同
4.没有this, 通过hooks的方式设置选项式API转变组合式API
5.对TS的支持diff算法的优化性能提升
Vue3 组合式Api及其作用
reactive 和 ref 是用来创建响应式数据的函数。
ref 用于创建一个包含单一值的响应式引用可以通过 .value 属性访问其值。
reactive 用于创建一个包含多个属性的响应式对象。
toRefs 用于将一个响应式对象转换为普通对象对象的每个属性都被包装成 ref使得对象的属性可以像 ref 一样使用。
computed 用来创建计算属性依赖于响应式数据并在依赖数据更新时自动重新计算其值。
watch 用来监视指定的响应式数据或计算属性并在其变化时执行特定的操作。
watchEffect 会立即执行一个函数并响应其内部响应式数据的变化。
生命周期钩子路由等
虚拟 DOM、diffing 算法、key
虚拟 DOM 比较“轻”真实 DOM 比较“重”因为虚拟 DOM 是内部在用无需真实 DOM 上那么多的属性。本质是object类型的对象(一般对象)。虚拟DOM最终会被转化为真实DOM呈现在页面上。
diffing 算法对于页面的更新内部会调用diffing算法将旧的虚拟dom和新的虚拟dom进行一层一层的节点比较如果节点相同就不重新渲染到真实dom如果不相同就重新渲染。最小的对比单位是一个节点。
key的作用key作为节点的表示在节点发生更新的时候起着重要作用。在状态发生改变后新旧虚拟dom发生比较先比较新dom中是否有相同key值的节点如果有则进行比较节点如果没有则直接渲染新的节点。 key属性是DOM元素的唯一标识
最好使用每条数据的唯一标识作为key比如id、手机号、身份证号、学号等唯一值
禁止使用整个 item会造成性能问题
简述 Vue 单页面和传统的多页面区别
单页面应用(SPA)通俗一点说就是指只有一个主页面的应用浏览器一开始要加载所有必须的 html,iscss。所有的页面内容都包含在这个所谓的主页面中。但在写的时候还是会分开写(页面片段)然后在交互的时候由路由程序动态载入单页面的页面跳转仅刷新局部资源。多应用于pc端
多页面(MPA)指一个应用中有多个页面页面跳转时是整页刷新
单页面的优点用户体验好快内容的改变不需要重新加载整个页面基于这一点 spa 对服务器压力较小;前后端分离;页面效果会比较炫酷(比如切换页面内容时的专场动画)。
单页面缺点不利于 seo;导航不可用如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能所以需要自己建立堆栈管理);初次加载时耗时多;页面复杂度提高很多
vue单页面不利于seo改成多页面为什么也不利于seo
因为Vue是需要在创建前生命周期调用后才开始渲染页面的
vue项目性能优化
1、v-for 遍历必须加 keykey 最好是 id 值且避免同时使用 v-if
2、防止内部泄露组件销毁后把全局变量和时间销毁
3、图片、路由、懒加载第三方插件的按需加载
4、防抖、节流的运用
5、服务端渲染 SSR or 预渲染由于浏览器在渲染出页面之前需要先加载和解析相应的 html、css 和 js 文件为此会有一段白屏的时间可以添加loading或者骨架屏幕尽可能的减少白屏对用户的影响体积优化
注意SSR也就是服务端渲染也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成然后再把html直接返回给客户端。SSR有着更好的SEO、并且首屏加载速度更快等优点。
6、减少不必要的请求
7、使用插件等进行打包优化
vue中的data为什么是一个函数
1 隔离作用域 2 实例化多个组件
当组件被复用时如果data是一个对象那么所有的组件实例将共享同一个数据对象这意味着一个组件的修改会影响到其他组件。
所以把data设置为工厂函数数据不会相互影响。
webPage 和 Vite
Loader 和 Plugin
功能不同
Loader: Loader 主要用于处理文件类型的转换和处理比如将 ES6/ES7 代码转换成ES5 代码将LESS/SASS/CSS 文件转换成浏览器可识别的CSS 文件等
Plugin: Plugin 主要用于在打包过程中做一些额外的处理工作比如文件压缩、代码分离、资源优化、生成 HTML 文件等。
作用范围不同
Loader 是针对于每个文件进行处理的每个文件都会经过 Loader 进行转换处理因此 Loader 的作用范围比较小。
Plugin 是针对于整个项目进行处理的它们能够修改打包的结果、优化打包过程、生成文件等。
Vite 快速的冷启动按需编译不用等待整个项目编译完成。
Vite打包
vue底层是rollup 和 esbuild在起作用
npm run build 后 打包生成 dist 文件给后端部署
1 配置打包文件和打包后位置
默认是
vite.config.ts 中的配置 rollupOptions 中 output 设置新的文件位置
export default defineConfig({plugins: [vue()],build: {rollupOptions: {output: {entryFileNames: js/[name].[hash].js,chunkFileNames: js/[name].[hash].js,assetFileNames(assetInfo){if(assetInfo.name.endsWith(.css)){return css/[name].[hash].css}if([.png, .jpg, .jpeg, .wenp, .svg, .git].some(ext assetInfo.name.endsWith(ext))){return img/[name].[hash].[ext]}return assets/[name].[hash].[ext]}}}}
}) 2 配置分包控制每次build的时候进行包的那些打包和那些不打包
分包策略 就是把不会常规更新的文件单独打包处理。
vite 在进行打包的时候会在文件名中添加一个hash值这个hash值与文件内容有关当文件内容发生变化时这个hash值就会发生变化。 之所以使用这个hash值的方式就是为了让浏览器能够在文件内容更新时及时地去重新请求新的资源。
manualChunks
export default defineConfig({plugins: [vue()],build: {rollupOptions: {// manualChunks: {// aaa: [lodash, vue],//}manualChunks(id){// 把 node_modules 下的不需要重复打包的文件 分包成 vendorif(id.includes(node_modules)){return vendor}console.log(id)}}}
})
配置打包后的文件名处理浏览器硬性清除缓存问题。打包配置HASH后缀
3 vite 打包压缩配置需要一个插件 vite-plugin-compression
/*** 文件压缩的配置 */import { defineConfig} from vite
import { compression } from vite-plugin-compression2
export default defineConfig({plugins:[// 就是使用这个插件实现的文件压缩compression({threshold:2000, // 设置只有超过 2k 的文件才执行压缩deleteOriginalAssets:false, // 设置是否删除原文件skipIfLargerOrEqual:true, // 如果压缩后的文件大小与原文件大小一致或者更大时不进行压缩// 其他的属性暂不需要配置使用默认即可})]
})
使用vue-cli或者vite创建出来的项目是不具备多端兼容的其中的路由方式、接口请求方式、标签等等。使用taro或uniapp为底层框架做了多端适配引入vue可以做多端系统。
VUE项目每次打包的版本号是可以配置不同编码哈希值的。这样的话不用线上强制刷新。 场景题
1 购物车页面的制作逻辑
拿到datafor循环设置状态async await根据图片名称异步调用图片点击勾选时更改状态利用 Computed 进行计算删除购物利用状态和过滤器进行操作。
2 Vue首页加载优化
懒加载路由组件 异步组件结合Suspense 减少首页组件数量 图片优化 代码优化 缓存 服务器端渲染
3 一些多端兼容问题
3.1 手机端快速向下滚动时IOS浏览器的地址栏和任务栏会隐藏快速向上滚动时会显示缓慢滚动不改变此时点击弹出层时就会出现各种各样的页面布局影响。
解决方法在打开弹出层时把滚动条位置设置为0的基础上加上 1. 弹出层不占满手机大小 2. 弹出层的大小随手机的变化而变化
3.2 小程序谷歌地图 web-view 传值时H5和app 无法使用同一个方法 H5 无法使用 web-view 的 message 方法而 app 无使用 web-view 存储区。
解决方法分开页面跳转进行不同的操作。H5 直接使用 本地储存进行地址传值。app 则通过 web-view 自身的 message 进行传值
4 uniapp分包小程序
4.1 配置manifest.jsonoptimization:{subPackages:true}
4.2 在pages.json中新建数组subPackages数组中包含两个参数root为子包的根目录pages子包由哪些页面组成参数同pages
4.3 注意主包和分包是不能再同一目录下在构建uniapp项目时可以考虑一下目录结构以便后期进行分包 小程序分包是将小程序的代码和资源分割成多个包主要用于降低主包体积提升加载速度。适合大型小程序能按需加载。 小程序独立分包是指某个分包可以独立于主包运行不需要主包中的代码和资源。适用于功能相对独立且体积较大的模块比如复杂的游戏或工具。 小程序分包预加载允许在用户进入某个页面之前提前加载该分包的资源确保用户体验流畅。常用于用户可能频繁访问的功能以减少等待时间。
5 前后端加密心理医生信息资料文章加密
传递重要参数加密、登录加密
密钥固定加密前后端无需传递密钥只需传递加密完的字符就行了
动态密钥加密前端生成随机密钥将加密好参数和密钥一起发送给后端
Crypto.JS是一个流行的JavaScript加密库支持多种加密算法包括AESDESRC4等加密方式或者md5,SHA等哈希散列。
import CryptoJS from crypto-js;
// AES加密 要加密的内容 密钥
const ciphertext CryptoJS.AES.encrypt(my message, secret key 123).toString();
console.log(ciphertext);
// AES解密 要解密的内容 密钥
const bytes CryptoJS.AES.decrypt(ciphertext, secret key 123);
const originalText bytes.toString(CryptoJS.enc.Utf8);
console.log(originalText); 6 阿里巴巴矢量库图标导入
https://blog.csdn.net/weixin_59528719/article/details/136343957
按照官方配置后类名就能输出对应的图标借助before
.icon-test:before{ content: \e8c5}
7 前端分页
前端分页调接口拿到数据存放所有数据的数组存放当前页面数据的数组设置keyWordpagesize等查询参数。
state.showList state.list.filter(item item.name.includes(state.keyWord)).slice((state.currentPage - 1) * state.pageSize, state.currentPage * state.pageSize)state.total state.list.filter(item item.name.includes(state.keyWord)).length
8 滚动分页
监听滚动事件在Vue组件中可以使用window对象的scroll事件来监听用户滚动。计算滚动位置确定用户是否滚动到页面底部通常是通过比较滚动位置和页面高度的差异来实现的。加载更多数据当用户滚动到底部时触发加载更多数据的操作例如获取下一页的内容。
9 多表单处理
通用的数据使用VueX存储分页展示组件Suspense异步加载、延迟加载loading扩展的数据懒加载
10 图片懒加载
现在很多组件库都可以直接加 lazy 设置图片懒加载。
图片懒加载 监听图片是否进入到可视区正式进入可视区之后将图片url数据交给img标签的src属性。
11 虚拟滚动
VueUse 是一个基于 Vue 3 的插件库。
VueUse 提供了大量的功能性钩子函数和工具函数包括但不限于
useLocalStorage用于在 Vue 组件中方便地使用 localStorage。
useClipboard用于在 Vue 组件中方便地操作剪贴板。
useMouse用于获取鼠标事件信息的钩子函数。
useDebounce 和 useThrottle用于创建防抖和节流的函数。
useIntersectionObserver用于观察元素是否进入视口的钩子函数。 //图片加载失败所显示的默认图片
import defaltImg from /assets/images/200.png
// 引入监听是否进入视口
import { useIntersectionObserver } from vueuse/core
export default {// 需要拿到main.js中由createApp方法产出的app实例对象install (app) {// app实例身上有我们想要的全局注册指令方法 调用即可app.directive(imgLazy, {mounted (el, binding) {// el:img dom对象// binding.value 图片url地址// 使用vueuse/core提供的监听api 对图片dom进行监听 正式进入视口才加载// img.src urlconst { stop } useIntersectionObserver(// 监听目标元素el,([{ isIntersecting }], observerElement) {if (isIntersecting) {// 当图片url无效加载失败的时候使用默认图片替代el.onerror function () {el.src defaltImg}el.src binding.valuestop()}})}})}
}img v-imgLazyitem.picture alt JS实现虚拟滚动注意点和代码
滚动条其实是嵌套父盒子里面跟显示元素同级的盒子的滚动条。滚动条的高度是所有元素的高度。
每一个列表的高度固定父元素的高度固定相除得出显示元素的个数slice、map函数再加上Math.ceil的四舍五入进行设置滚动的时候不会出现空一截的情况记住开始开始index和结束位置的index
!DOCTYPE html
htmlheadmeta charsetutf-8title原生JS虚拟滚动列表/titlestyle* {margin: 0;padding: 0;}.list-wrapper {width: 230px;height: 100px;border: 1px solid pink;margin: 10px auto;position: relative;overflow-y: scroll;}.scroll-bar {width: 100%;}.data-box {position: absolute;left: 0;top: 0;}.list-item {width: 100px;height: 20px;background-color: #ccc;}/style
/headbodydiv idappdiv classlist-wrapper idlistWrapperdiv classscroll-bar idscrollBar/divdiv classdata-box iddataBox!-- 列表项将在这里动态生成 --/div/div/divscript(function () {const listWrapper document.getElementById(listWrapper);const dataBox document.getElementById(dataBox);const scrollBar document.getElementById(scrollBar);const itemHeight 20;const listWrapperHeight 100;const listData []for (let i 1; i 50; i) {listData.push(i)}console.log(listData)function renderList(startIndex, endIndex) {const items listData.slice(startIndex, endIndex).map(item div classlist-item${item}/div).join();dataBox.innerHTML items;}function updateScroll() {const scrollTop listWrapper.scrollTop;const scrollCount Math.floor(scrollTop / itemHeight);const startIndex scrollCount;const showCount Math.ceil(listWrapperHeight / itemHeight);const endIndex startIndex showCount;const startOffset startIndex * itemHeight;dataBox.style.transform translate3d(0, ${startOffset}px, 0);renderList(startIndex, endIndex);}// 设置 scrollBar 的高度const totalHeight listData.length * itemHeight;scrollBar.style.height ${totalHeight}px;// 初始化渲染updateScroll();// 监听滚动事件listWrapper.addEventListener(scroll, updateScroll);})();/script
/body/html 12 聚合支付详解
新西兰项目微信支付、支付宝、VISA、PayPal、cash选完订单选择支付方式后端返回地址进入地址。如果支付成功后端返回支付页面在聚合支付后台可以配置地址加上完成订单id前端做判断如果存在完成订单的id则支付成功跳到订单详情页面如果不存在订单id则用户未支付再次回到餐厅页面。
13 谷歌地图 多端适配问题
要钱的公司申请的apiKey 还有秘钥
pubilc 引进 谷歌地图 获取定位传回app
getlocation
小程序谷歌地图 web-view 传值时H5和app 无法使用同一个方法 H5 无法使用 web-view 的 message 方法而 app 无使用 web-view 存储区。
vue谷歌地图 vue-google-maps 插件
14 海康摄像头
进入官网下载对应的web视频插件script标签引入js文件
div标签类似echart生成图表的做法结合WebControl后端获取每个学校不同区域的摄像头设备号和端口号进行连接画面
15 Excel导入导出 PDF预览打印
excel导入使用Element UI的文件上传组件获取文件并使用xlsx库解析Excel文件内容。
excel导出可以前端操作xlsx和file-saver使用xlsx库生成Excel文件并使用file-saver库将其保存到用户设备。也可以后端操作后端下载文件然后生成地址的方式
PDF预览、使用vue-pdf插件或者iframe标签
export function postExportData(data) {return request({method: POST,url: /synthetic/exportTodoMatterList,responseType: blob,data}).then(res {console.log([res]: , res)// const fileName res.headers[Content-Disposition].split(filename)[1]const fileName 123.xlsxconst url URL.createObjectURL(new Blob([res.data]));const link document.createElement(a);link.download fileNamelink.href urllink.click()})
}
file(文件流)、bolb(本地流)、base64(二进制流)三者可以互相转换
以下的方法无论是图片、excel文件、PDF都可使用设置responseType结合URL.createObjectURL生成链接然后自点击进行下载 16 小程序支付 小程序注册微信支付商户号绑定小程序ID
1 前端调用uniapp登录接口这个code用户登录凭证有效期5分钟可以换取 opendIdunionIdsession_key等核心信息 uni.login({provider: weixin, // 使用微信登录success: (res) {// 这个code用户登录凭证有效期5分钟可以换取 opendIdunionIdsession_key等核心信息res.code}
});
2 发送请求调用微信官方接口用code凭证换取用户openId
uni.request({// 微信官方接口url: https://pi.weixin.qq.com/sns/jscode2session,data: {appid: 小程序appid,secret: 小程序密钥,js_code: 上一步获取的code,// 固定值grant_type: authorization_code,},success: (res {// 获取openId 用户真实唯一IDconsole.log(res.data.openId)})
})
3 调用公司后端接口获取支付核心数据
uni.request({url: 公司后端接口,data: {金额订单号},methodPOST,success: (res {// 获取openId 用户真实唯一IDconsole.log(res.data.openId)})
})
4 调用微信官方支付接口弹出支付页面
wx.requestPayment({timeStamp: 时间戳,noncesTR: 随机字符,package: prepay_id,signType: MD5,paySign: 后端返回的签名,success(res){},fail(res){}
})
17 生成画布分享朋友圈
设置是全局分享功能如果是点击右上角的三个点得分享功能 onShareAppMessage 分享朋友 onShareTimeline 分享朋友圈 onShareTimeline(res) { //发送到朋友圈onShareAppMessage(res) { //发送给朋友// 获取加载的页面let pages getCurrentPages();// 获取当前页面的对象let view pages[pages.length - 1];//分享的页面路径let path /${view.route};let imageUrl /static/11111.pngreturn {title: czxml,path: path,imageUrl: imageUrl,success(res) {console.log(success(res), res);uni.showToast({title: 分享成功})},fail(res) {console.log(fail(res), res);uni.showToast({title: 分享失败,icon: none})}}},
如果是通过自己设置得分享按钮 button open-typeshare
button clickclickShare stylewidth: 100rpx; height: 100rpx; border: none; opacity: 0; open-typeshare/button
18 餐桌独立点单和JSBridge 生成餐厅桌椅摆放图
Safari浏览器自带的扫一扫扫描二维码进入餐桌传来餐桌ID改变餐桌状态和生成临时用户信息给后端结束订单付款的时候工作人员点击结束订单。
和安卓开发一起联调给我个地址使用script标签引入 基本的 JSBridge当进入制定餐桌页面时就是我的前端页面调用JSBridge方法判断有没有登录有没有权限进行设置sucess返回状态有则进行页面展示使用拖拉拽API和画布生成图片详解然后保存给后端。如果没有权限则使用JSBridge.openWindow打开app本身的登录页面进行登录。 window.JSBridge.openWindow({url: http://yqt-dev.digitalgd.com.cn/default/#/pages/mine/personal/company/index})
通过设置鼠标的按下、移动、松开事件再根据鼠标的偏移量设置元素的偏移。
19 流程问题
新建计划、计划分派、检查方案、检查准备预通知、检查报告、综合评定报告、结果处置。
20 请求的封装包括不同环境
.env 判断不同坏境
开发.env.development、正式.env.production、测试.env.test
NODE_ENV development/production/test
VUE_APP_API_URL http://*****
VUE_APP_SERVER_URL /api
// 创建axios实例
const request axios.create({baseURL: getBaseUrl(),// 所有的请求地址前缀部分(没有后端请求不用写)timeout: 80000, // 请求超时时间(毫秒)// headers: {// 设置后端需要的传参类型// Content-Type: application/json,// token: x-auth-token,//一开始就要token// X-Requested-With: XMLHttpRequest,// },
})// request拦截器请求拦截
request.interceptors.request.use(config {// 如果你要去localStor获取token,(如果你有)// let token localStorage.getItem(x-auth-token);// if (token) {//添加请求头//config.headers[Authorization]Bearer token// }return config},error {// 对请求错误做些什么Promise.reject(error)}
)// response 拦截器响应拦截
request.interceptors.response.use(response {// 对响应数据做点什么return response.data},error { // 对响应错误做点什么//响应错误let message ;if (error.response error.response.status) {const status error.response.status;switch (status) {case 404:message 请求地址出错;break;default:message 请求失败;}return Promise.reject(error);}return Promise.reject(error);}
) 总结配置.env文件设置不同环境下的请求地址创建axios实例设置请求头请求地址和请求超时时间限制。设置请求拦截器关于一些接口判断系统是否存在token做相对应处理设置响应拦截关于接口返回的状态码结合当前组件库做出对应的提示。
前端中断请求的方式 AbortController
21 eChart
需要定义宽高找到IDinit元素setOption当离开页面时要去销毁。
import * as echarts from echarts;var chartDom document.getElementById(main);
var myChart echarts.init(chartDom);
var option;option {xAxis: {type: category,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]},yAxis: {type: value},series: [{data: [150, 230, 224, 218, 135, 147, 260],type: line}]
};option myChart.setOption(option);
佛山市地图
获取地图的GeoJSONDataV.GeoAtlas地理小工具系列阿里云数据可视化平台点击你想要生成的地图省市生成JSON数据准备容器放置JSON数据进行展示和resize跳转。 22 webscoket 流式读取
fetch 使用 async await 。第一个await等待的是响应头第二个await等待的是响应体在第二个await进行操作结合 getReader 可读器reader.read() 一小部分一小部分读取done【false还未读完】和value值TextDecoder解码器二进制加码成文本。使用while循环。
const url http://xxx.com/posts;async function getResponse() {const resp await fetch(url, {method: GET,headers: {Content-Type: application/json}});const reader resp.body.getReader();const decoder new TextDecoder();while (true) {const {done,value} await reader.read();if (done) break;const txt decoder.decode(value);console.log(done);console.log(txt);}
}getResponse();23 富文本发布文章在小程序和PC端不兼容问题
PC富文本使用的是 wangEditor 5
小程序video sourse无法播放原因PC的话 sourse 和 src都能设置视频地址两者需要判断不同环境进行不同字符串拼接
24 动态设计普查心理问卷和答完问卷正确错误及分数展示
左侧点击生成题目右侧设计题目类型标题必填分数排序
每一种题型都做成组件使用components循环引出。
使用JSON转字符格式大致如下
{ id: , type: , title: , score: , required: true, answer: , option: [], sort: , }
25 前端拖拽排序
v-drag
JS拖拽
1 设置 元素 属性 draggabletrue
2 找到父元素事件委托监听拖拽开始事件 ondragstart添加样式
3 设置当元素被拖拽时改变元素样式记得使用setTimeout 控制样式使得被拖拽出来的本体和留在原地的本体出现样式上的区别
4 ondragenter 拖拽进入如果进入的父元素或者拖拽元素的本身则返回否则将进入的元素和拖拽元素进行位置切换使用 insertBefore 插入元素
5 当松开鼠标时dragend 事件 移除样式。
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlestyle.list-item {background-color: #266fff;border-radius: 5px;color: #fff;width: 250px;padding: 5px;margin-bottom: 10px;}.list-item.moving {background-color: transparent;color: transparent;border: 1px solid #ccc;}/style
/headbodydiv classlistdiv draggabletrue classlist-item1/divdiv draggabletrue classlist-item2/divdiv draggabletrue classlist-item3/divdiv draggabletrue classlist-item4/divdiv draggabletrue classlist-item5/div/div
/body
script// 拖拽排序在很多站点里面是非常常见的使用的API就是一个拖拽API// 1、让元素变的可拖拽 找到这些元素给这些元素加上 draggable 属性值为true这样就变得可拖拽了// 2、拖拽的时候样式得变 class为moving的样式const list document.querySelector(.list)// 用来记录当前拖拽的是哪个元素let sourceNode null// 用事件委托的方式 给父元素绑定事件list.addEventListener(dragstart, function (e) {// e.target 拖的是哪个元素// 当拖拽开始的时候要找到拖拽的那个元素给他添加类样式// 为什么要用setTimeout,不用的话拖拽的那个元素也会变成虚线就是添加了类样式后的样子// 它的样式取决于拖拽开始时候元素本身的样式需要在拖拽开始的时候保持原来的样式 把它变成异步的setTimeout(() {e.target.classList.add(moving)}, 0)sourceNode e.target})// 3、什么时候产生排序拖拽的时候把拖拽对象放到了某些元素之上这里就要监听拖拽进入事件list.addEventListener(dragenter, function (e) {// e.target 进入的是哪个元素e.preventDefault()// 排除掉一些情况比如拖拽的时候进入了父元素 或者 是本身自己if (e.target list || e.target sourceNode) returnconst children [...list.children]// 通过所处元素的下标来判断是上方还是下方const sourceIndex children.indexOf(sourceNode)const targetIndex children.indexOf(e.target)// console.log(sourceIndex, targetIndex)// 4、当拖拽的元素进入到别的元素身上的时候要做的一些事情if (sourceIndex targetIndex) {// console.log(下方)// 插入到那个元素下一个元素之前list.insertBefore(sourceNode, e.target.nextElementSibling)} else {// console.log(上方)list.insertBefore(sourceNode, e.target)}// console.log(sourceIndex)})// 拖拽完毕 松开鼠标list.addEventListener(dragend, function (e) {// 移除掉类样式即可sourceNode.classList.remove(moving)})
/script/html
26 前端文章水印及其防止篡改功能
现在很多组件库都有自己的水印组件 waterMark。
1 获取该要加水印的 div
2 使用canner结合文章盒子大小生成背景水印图片
// canvas 生成 水印背景
watermarkBg() {const canvas document.createElement(canvas);const devicePixelRatio window.devicePixelRatio || 1;const fontSize this.config.fontSize * devicePixelRatio;const font fontSize px Microsoft YaHei, sans-serif;const ctx canvas.getContext(2d);if (!ctx) {return null}ctx.font font;const { width } ctx.measureText(this.config.text);const canvasSize Math.max(100, width) this.config.gap * devicePixelRatiocanvas.width canvasSize;canvas.height canvasSize;ctx.translate(canvasSize / 2, canvasSize / 2);ctx.rotate((Math.PI / 180) * 45);ctx.fillStyle rgba(0,0,0,0.3);ctx.font font;ctx.textAlign center;ctx.textBaseline middle;ctx.fillText(this.config.text, 0, 0);return {base64: canvas.toDataURL(image/png),size: canvasSize / devicePixelRatio}
}
3 把背景水印图片加到 div 上重置水印当有人把水印元素删除或者修改时重新执行该方法
resetWatermark() {if (!this.config.wrapperElement) {console.log(未获取到父元素);return}// 由于监听元素变化后会重新创建此处做判断如果有水印元素则要删除重新创建防止水印元素重复创建if (this.watermarkElement) {this.watermarkElement.remove();}const bg this.watermarkBg()if (!bg) {return}const { base64, size } bgthis.watermarkElement document.createElement(div);this.watermarkElement.style.position absolute;this.watermarkElement.style.backgroundImage url(${base64});this.watermarkElement.style.backgroundSize ${size}px ${size}px;this.watermarkElement.style.backgroundRepeat repeat;this.watermarkElement.style.zIndex 9999this.watermarkElement.style.pointerEvents none;this.watermarkElement.style.inset 0this.config.wrapperElement.appendChild(this.watermarkElement);
}
4 使用 MutationObserver 监听用户是否进行篡改水印 DOM如果篡改进行水印重置 // 监听操作变化const ob new MutationObserver((entries) {for (const entry of entries) {// 删除for(const dom of entry.removedNodes) {if(dom div) {console.log(水印被删除);resetWatermark();return;}}// 修改if(entry.target div) {console.log(水印被修改);resetWatermark();return;}}}) 完整代码
templatediv classwatermark-container refparentRefslot/slot/div
/templatescript setupimport useWatermarkBg from ./useWatermarkBg;import defineProps, { ref, onMounted, onUnmounted } from vueconst props defineProps({text: {type: String,required: true,default: watermark},fontSize: {type: Number,default: 40},gap: {type: Number,default: 20},});const bg useWatermarkBg(props);const parentRef ref(null);let div;// 重置水印function resetWatermark() {if(!parentRef.value) return;if (div) {div.remove();}const { base64, size } bg.value;div document.createElement(div);div.style.position absolute;div.style.backgroundImage url(${base64});div.style.backgroundSize ${size}px ${size}px;div.style.backgroundRepeat repeat;div.style.zIndex 9999;div.style.inset 0;parentRef.value.appendChild(div);}onMounted(resetWatermark);// 监听操作变化const ob new MutationObserver((entries) {for (const entry of entries) {// 删除for(const dom of entry.removedNodes) {if(dom div) {console.log(水印被删除);resetWatermark();return;}}// 修改if(entry.target div) {console.log(水印被修改);resetWatermark();return;}}})onMounted(() {ob.observe(parentRef.value, {childList: true,subtree: true,attributes: true,})})onUnmounted(() {// 取消监听ob.disconnect();})
/scriptstyle scoped.watermark-container {position: relative;}
/style
27 多套语言系统的引入
设置多套js进行存储不同数据页面根据用户设置的语言进行选择展示。 i18n 插件
28 为什么要用webSocket?
实时通信低延迟、双向通信 减少网络开销持久连接、更小的传输数据量
node 包管理工具npmcnpmnvmpnpmyarn
买个服务器作为代码仓库registry在里面放所有需要被共享的代码 发邮件通知 jQuery、Bootstrap、Underscore 作者使用 npm publish 把代码提交到 registry 上分别取名 jquery、bootstrap 和 underscore注意大小写 社区里的其他人如果想使用这些代码就把 jquery、bootstrap 和 underscore 写到 package.json 里然后运行 npm install npm 就会帮他们下载代码 下载完的代码出现在 node_modules 目录里可以随意使用了
npm 是 Node.js 的默认包管理工具用于安装、管理和发布 JavaScript 模块。它是一个强大的工具支持管理项目依赖、执行脚本、发布包等功能。
cnpmChina npm 是 npm 的镜像专为中国用户优化使用 cnpm 可以加速 npm 的包下载和安装。使用的是国内的镜像源。
nvm (Node Version Manager)是 Node.js 的版本管理工具允许用户在同一台机器上安装和切换多个 Node.js 版本。可以用于在不同项目中使用不同的 Node.js 版本同时避免全局环境的版本冲突。
pnpm 是一个快速、节省磁盘空间的包管理器与 npm 和 yarn 不同它采用硬链接和符号链接的方式共享依赖。可以减少依赖的重复安装节省磁盘空间并且速度比传统的 npm 和 yarn 快。
yarn 是 Facebook 开发的包管理工具旨在解决 npm 的一些性能和安全问题。它使用并行安装和缓存等策略来提高速度并且支持离线安装和版本锁定等功能。
不要在一个项目上使用多种安装方式不然会有兼容性报错风险。