当前位置: 首页 > news >正文

重庆合川企业网站建设丹东谁家做网站

重庆合川企业网站建设,丹东谁家做网站,怎么开网店新手入门,施工企业降本增效的方法和措施frontend Vue2 学习内容参考 /在线运行 Element 学习内容参考 /视频教学 vue2 1. vue 实例 当一个 Vue 实例被创建时#xff0c;它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中 但是当使用Object.freeze()#xff0c;会阻止修改现有的 property#x…frontend Vue2 学习内容参考 /在线运行 Element 学习内容参考 /视频教学 vue2 1. vue 实例 当一个 Vue 实例被创建时它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中 但是当使用Object.freeze()会阻止修改现有的 property也意味着响应系统无法再追踪变化。 var obj {foo: bar } ​ Object.freeze(obj) ​ new Vue({el: #app,data: obj }) 不要在选项 property 或回调上使用箭头函数因为箭头函数并没有 thisthis 会作为变量一直向上级词法作用域查找直至找到为止经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。 2. 模板语法 render: 如果熟悉虚拟 DOM 并且偏爱 JavaScript 的原始力量也可以不用模板直接写渲染 (render) 函数使用可选的 JSX 语法。 在站点上动态渲染的任意 HTML 可能会非常危险因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值绝不要对用户提供的内容使用插值。因为如果用户输入内容包含恶意脚本这些脚本会被执行,并且直接解析并渲染 HTML 内容。而{{ }}会被转义为纯文本,会更安全。 js模板表达式 模板表达式都被放在沙盒中只能访问全局变量的一个白名单如 Math 和 Date 。不应该在模板表达式中试图访问用户定义的全局变量。 3. v-指令 指令支持动态参数 不推荐同时使用 v-if 和 v-for。因为当它们一起使用时v-if 会优先于 v-for 被处理这可能会导致一些意外的行为和性能问题。可以使用计算属性进行过滤, 也可以将 v-if 置于外层元素 v-for 在遍历对象时会按 Object.keys() 的结果遍历但是不能保证它的结果在不同的 JavaScript 引擎下都一致。如果你需要确保属性的遍历顺序是一致的, 可以使用map 替换数组: filter()、concat() 和 slice()。它们不会变更原始数组而总是返回一个新数组 当ul标签使用v-for, 使用is渲染组件, istodo-item attribute。因为在 ul 元素内只有 li 元素会被看作有效内容。这样做实现的效果与 todo-item 相同但是可以避开一些潜在的浏览器解析错误。这是因为这些结构有严格的子元素要求。例如ul 元素只能包含 li 元素作为其直接子元素。查看 DOM 模板解析说明 来了解更多信息。 使用修饰符时顺序很重要相应的代码会以同样的顺序产生。因此用 v-on:click.prevent.self 会阻止所有的点击而 v-on:click.self.prevent 只会阻止对元素自身的点击。 4. 组件 组件是可复用的 Vue 实例所以它们与 new Vue 接收相同的选项 一个组件的 data 选项必须是一个函数因此每个实例可以维护一份被返回对象的独立的拷贝,否则可能影响到其他实例 .prop - 作为一个 DOM property 绑定而不是作为 attribute 绑定。(差别在哪里) is渲染组件,使用.vue,template 是不会有限制的 HTML 中的 attribute 名是大小写不敏感的所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名 但是重申一次如果你使用字符串模板那么这个限制就不存在了。 这个 prop 用来传递一个初始值这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下最好定义一个本地的 data property 并将这个 prop 用作其初始值 场景: 网络请求res.data中的属性可能会被提示未定义 props: [initialCounter], data: function () {return {counter: this.initialCounter} } prop 验证 注意那些 prop 会在一个组件实例创建之前进行验证所以实例的 property (如 data、computed 等) 在 default 或 validator 函数中是不可用的 组件可以接受任意的 attribute,从外部提供给组件的值会替换掉组件内部设置好的值。 class 和 style attribute 会稍微智能一些即两边的值会被合并起来从而得到最终的值form-control date-picker-theme-dark。 若想要在一个组件的根元素上直接监听一个原生事件, Vue 提供了一个 $listeners property,包含了作用在这个组件上的所有监听器 Vue.component(base-input, {inheritAttrs: false,props: [label, value],computed: {inputListeners: function () {var vm this// Object.assign 将所有的对象合并为一个新对象return Object.assign({},// 我们从父级添加所有的监听器this.$listeners,// 然后我们添加自定义监听器// 或覆写一些监听器的行为{// 这里确保组件配合 v-model 的工作input: function (event) {vm.$emit(input, event.target.value)}})}},template: label{{ label }}inputv-bind$attrsv-bind:valuevaluev-oninputListeners/label }) .sync 修饰符 处理组件之间的双向数据流 但vue3已移除 父级模板里的所有内容都是在父级作用域中编译的子模板里的所有内容都是在子作用域中编译的。 具名插槽 # 在每个 new Vue 实例的子组件中其根实例可以通过 $root property 进行访问。 // 获取根组件的数据 this.$root.foo 但是中大型应用就要使用vuex了 类似的,$parent property 可以用来从一个子组件访问父组件的实例 但是会失控,所以推荐依赖注入 目录树组件循环引用,可以使用webpack 的异步 import 5. 过渡 vue在插入,更新或者移除DOM时,提供多种不同方式的应用过渡效果,包括以下工具 css 过渡和动画 第三方css动画库 Animate.css js钩子函数 第三方js动画库,如velocity.js 5.1 单元素/组件的过渡 vue提供了transition的分装组件,为元素添加过度 div iddemobutton v-on:clickshow !showToggle/buttontransition namefadep v-ifshowhello/p/transition /div ​ style//元素从进入到离开 过程.fade-enter-active, .fade-leave-active{transition:opacity .5s;}//元素在刚开始进入和离开时 动作.fade-enter, .fade-leace-to{opacity: 0} /style ​ 5.1.1 过渡的类名 在进入/离开的过渡中会有 6 个 class 切换。 v-enter定义进入过渡的开始状态。在元素被插入之前生效在元素被插入之后的下一帧移除。 v-enter-active定义进入过渡生效时的状态。在整个进入过渡的阶段中应用在元素被插入之前生效在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间延迟和曲线函数。 v-enter-to2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除)在过渡/动画完成之后移除。 v-leave定义离开过渡的开始状态。在离开过渡被触发时立刻生效下一帧被移除。 v-leave-active定义离开过渡生效时的状态。在整个离开过渡的阶段中应用在离开过渡被触发时立刻生效在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间延迟和曲线函数。 v-leave-to2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除)在过渡/动画完成之后移 5.1.2 自定义过度的类名 我们可以通过以下 attribute 来自定义过渡类名 enter-class enter-active-class enter-to-class (2.1.8) leave-class leave-active-class leave-to-class (2.1.8) link hrefhttps://cdn.jsdelivr.net/npm/animate.css3.5.1 relstylesheet typetext/css ​ div idexample-3button clickshow !showToggle render/buttontransitionnamecustom-classes-transitionenter-active-classanimated tadaleave-active-classanimated bounceOutRightp v-ifshowhello/p/transition /div 5.2 初始渲染的过度 transition appear!-- ... -- /transition 5.2.1自定义css类名 transitionappearappear-classcustom-appear-classappear-to-classcustom-appear-to-class (2.1.8)appear-active-classcustom-appear-active-class !-- ... -- /transition 5.2.2 自定义js钩子 transitionappearv-on:before-appearcustomBeforeAppearHookv-on:appearcustomAppearHookv-on:after-appearcustomAfterAppearHookv-on:appear-cancelledcustomAppearCancelledHook !-- ... -- /transition 5.3 多个元素的过度 transitiontable v-ifitems.length 0!-- ... --/tablep v-elseSorry, no items found./p /transition 5.3.1 过渡模式 in-out新元素先进行过渡完成之后当前元素过渡离开。 out-in当前元素先进行过渡完成之后新元素过渡进入。(常用) transition namefade modeout-in!-- ... the buttons ... -- /transition 5.4 多个组件的过度 使用动态组件 transition namecomponent-fade modeout-incomponent v-bind:isview/component /transition 5.5 列表过度 使用transition-group div idlist-demo classdemobutton v-on:clickaddAdd/buttonbutton v-on:clickremoveRemove/buttontransition-group namelist tagpspan v-foritem in items v-bind:keyitem classlist-item{{ item }}/span/transition-group /div 6. 可复用性组合 6.1 JSX 7. 测试 Vue 组件通常包含 .vue 文件里面包含模板、脚本和样式。这种单文件组件SFC格式并不是原生 JavaScript 或 TypeScript 能直接识别的。因此vue-jest 使用 Babel 来将 .vue 文件转换为可被 Jest 识别的格式。 Jest 本身依赖 Babel 来处理 Vue 单文件组件及 ES 模块。babel-jest 可以帮你将非标准的 J 7.1 步骤 vue2 7.1.1 ts 安装jest npm install jest --save-dev 配置jest 在根目录下创建jest.config.js module.exports {moduleFileExtensions: [js, vue],moduleNameMapper: {^/(.*)$: rootDir/src/$1},transform: {^.\.js$: babel-jest,.*\.vue$: vue-jest},snapshotSerializers: [jest-serializer-vue],// 在Vue单元测试中使用了v-model, 需要添加一下配置,请参考官方文档.// https://vue-test-utils.vuejs.org/guides/common-tips.html#mocking-components-that-use-v-model// setupFiles: [rootDir/tests/unit/setup.js],testMatch: [rootDir/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)],testURL: http://localhost/ } moduleFileExtensions 中包含了Vue文件这是允许Vue文件被编译并测试的必要配置。 moduleNameMapper 是用来解析符号的。 transform 配置了如何转换代码vue-jest 转换.vue文件babel-jest 转换.js文件。 snapshotSerializers 在snapshot test中使用使快照测试更加容易。 testMatch 配置了测试文件的匹配规则。 testURL 配置了测试时浏览器的URL。 编写测试用例 import { shallowMount } from vue/test-utils import HelloWorld from /components/HelloWorld.vuedescribe(HelloWorld.vue, () {it(renders props.msg when passed, () {const msg new messageconst wrapper shallowMount(HelloWorld, {propsData: { msg }})expect(wrapper.text()).toMatch(msg)}) }) npm run jest 运行 7.1.2 babel 安装依赖 npm install --save-dev jest vue/test-utils babel-jest vue-jest 配置Jest 在项目根目录添加jest.config.js module.exports {preset: vue/cli-plugin-unit-jest,transform: {^.\\.vue$: vue-jest,^.\\.js$: babel-jest,},moduleFileExtensions: [js, vue],testMatch: [**/tests/**/*.spec.js], };* 确保Jest能够识别和处理Vue组件以及js文件 创建测试文件 放在test文件夹下,以.spec.js结尾 //shallowMount 用于浅层挂载一个 Vue 组件它只渲染组件的最外层不会递归渲染子组件适用于组件依赖的其他子组件较复杂时进行测试。 import {shallowMount} from vue/test-utils; import HelloWorld from /components/HelloWorld.vue; //describe 用于组织和分组相关的测试括号中的 HelloWorld.vue 作为测试套件的名称指明我们要测试的目标是 HelloWorld.vue 组件。 describe(HelloWorld.vue, () {//it 函数用于定义一个测试用例括号中的 renders props.msg when passed 是对测试的简短描述意思是“当传递 msg 属性时组件应该正确渲染出来”。it(renders props.msg when passed, () {//我们将在测试中传递msg作为组件的 props以测试它是否正确渲染出来。  const msg Hello Jest;//shallowMount 用于浅层挂载 HelloWorld 组件。  //wrapper 是一个包装器对象它包含了挂载后的组件实例并提供了访问和操作组件的方法比如获取 DOM 元素、触发事件等。  const wrapper shallowMount(HelloWorld, {propsData: {msg}});//这一行是断言assertion它使用 Jest 的 expect 函数来验证测试结果。//wrapper.text() 获取组件的文本内容包括组件的所有子元素。//toMatch 用于检查文本是否包含指定的字符串 msg即 Hello Jest。这个断言期望组件渲染的文本内容中包含传递的 msg。  expect(wrapper.text()).toMatch(msg);}); }); 7.2 报错 由于未知原因,我的js项目竟然必须安装types/jest,才可以正确引入jest,实在不知道为什么,先贴出来吧 yarn add --dev types/jest 8. 规模化 8.1 路由 8.2 状态管理 Redux 事实上无法感知视图层所以它能够轻松的通过一些简单绑定和 Vue 一起使用 8.3 服务端渲染 9. 安全 用户提供的 URL 永远需要通过后端在入库之前进行过滤.需要对该 URL 进行“过滤”以防止通过 javascript: 来执行 JavaScript Vue 要在模板内避免渲染 style 标签,避免用户伪造样式,推荐在style属性中使用对象语法,提供特定property值 向后端提供 CSRF token 为每个表单生成一个唯一的随机令牌并要求客户端在提交表单时也附带这个令牌。 10. axios 封装步骤 设置接口请求前缀 利用node环境变量来作判断用来区分开发、测试、生产环境 if (process.env.NODE_ENV development) {axios.defaults.baseURL http://dev.xxx.com } else if (process.env.NODE_ENV production) {axios.defaults.baseURL http://prod.xxx.com } 跨域 在本地调试的时候还需要在vue.config.js文件中配置devServer实现代理转发从而实现跨域 devServer: {proxy: {/proxyApi: {target: http://dev.xxx.com,changeOrigin: true,pathRewrite: {/proxyApi: }}}} 设置请求头与超时时间 大部分情况下请求头都是固定的只有少部分情况下会需要一些特殊的请求头这里将普适性的请求头作为基础配置。当需要特殊请求头时将特殊请求头作为参数传入覆盖基础配置 const service axios.create({...timeout: 30000, // 请求 30s 超时headers: {get: {Content-Type: application/x-www-form-urlencoded;charsetutf-8// 在开发中一般还需要单点登录或者其他功能的通用请求头可以一并配置进来},post: {Content-Type: application/json;charsetutf-8// 在开发中一般还需要单点登录或者其他功能的通用请求头可以一并配置进来}}, }) 封装请求方法 先引入封装好的方法在要调用的接口重新封装成一个方法暴露出去 // get 请求 export function httpGet({url,params {} }) {return new Promise((resolve, reject) {axios.get(url, {params}).then((res) {resolve(res.data)}).catch(err {reject(err)})}) }// post // post请求 export function httpPost({url,data {},params {} }) {return new Promise((resolve, reject) {axios({url,method: post,transformRequest: [function (data) {let ret for (let it in data) {ret encodeURIComponent(it) encodeURIComponent(data[it]) }return ret}],// 发送的数据data,// url参数params}).then(res {resolve(res.data)})}) } 把封装的方法放在一个api.js文件中 import { httpGet, httpPost } from ./http export const getorglist (params {}) httpGet({ url: apps/api/org/list, params }) 页面中就能直接调用 // .vue import { getorglist } from /assets/js/apigetorglist({ id: 200 }).then(res {console.log(res) }) 这样可以把api统一管理起来以后维护修改只需要在api.js文件操作即可 请求拦截器 请求拦截器可以在每个请求里加上token做了统一处理后维护起来也方便 // 请求拦截器 axios.interceptors.request.use(config {// 每次发送请求之前判断是否存在token// 如果存在则统一在http请求的header都加上token这样后台根据token判断你的登录情况此处token一般是用户完成登录后储存到localstorage里的token (config.headers.Authorization token)return config},error {return Promise.error(error)}) 响应拦截器 响应拦截器可以在接收到响应后先做一层操作如根据状态码判断登录状态、授权 // 响应拦截器 axios.interceptors.response.use(response {// 如果返回的状态码为200说明接口请求成功可以正常拿到数据// 否则的话抛出错误if (response.status 200) {if (response.data.code 511) {// 未授权调取授权接口} else if (response.data.code 510) {// 未登录跳转登录页} else {return Promise.resolve(response)}} else {return Promise.reject(response)} }, error {// 我们可以在这里对异常状态作统一处理if (error.response.status) {// 处理请求失败的情况// 对不同返回码对相应处理return Promise.reject(error.response)} }) 深入响应式原理 vue最独特的特性之一 Vue 遍历data中数据对象所有的 property并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。这些 getter/setter 对用户来说是不可见的但是在内部它们让 Vue 能够追踪依赖在 property 被访问和修改时通知变更 这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。 不能检测数组和对象的变化,,而Vue3中的proxy代理解决了这个问题 每个组件实例都对应一个 watcher windows事件直接赋给变量,不是响应式,需要在onMounted事件中进行监听 面试题 1. 首屏加载 首屏加载是用户体验中最重要的缓解 常见spa首屏优化方案 减小入口文件体积 路由懒加载 静态资源本地缓存 后端返回资源问题 采用HTTP缓存设置Cache-ControlLast-ModifiedEtag等响应头 采用Service Worker离线缓存 前端合理利用localStorage ui框架按需加载 element 按需加载 组件重复打包 假设A.js文件是一个常用的库现在有多个路由使用了A.js文件这就造成了重复下载 解决方案在webpack的config文件中修改CommonsChunkPlugin的配置 minChunks: 3 minChunks为3表示会把使用3次及以上的包抽离出来放进公共依赖文件避免了重复加载组件 图片资源压缩 对于所有的图片资源我们可以进行适当的压缩 开启GZip压缩 使用SSR SSRServer side 也就是服务端渲染组件或页面通过服务器生成html字符串再发送到浏览器 从头搭建一个服务端渲染是很复杂的vue应用建议使用Nuxt.js实现服务端渲染 2. 组件通讯 小型-Vue.observable 步骤 创建一个js文件 // 引入vue import Vue from vue // 创建state对象使用observable让state对象可响应 export let state Vue.observable({name: 张三,age: 38 }) // 创建对应的方法 export let mutations {changeName(name) {state.name name},setAge(age) {state.age age} } 在.vue文件中直接使用即可 templatediv姓名{{ name }}年龄{{ age }}button clickchangeName(李四)改变姓名/buttonbutton clicksetAge(18)改变年龄/button/div /template import { state, mutations } from /store export default {// 在计算属性中拿到值computed: {name() {return state.name},age() {return state.age}},// 调用mutations里面的方法更新数据methods: {changeName: mutations.changeName,setAge: mutations.setAge} } 3. Promise promise 异步编程解决方案 3.1 以往 多层异步操作 doSomething(function(result) {doSomethingElse(result, function(newResult) {doThirdThing(newResult, function(finalResult) {console.log(得到最终结果: finalResult);}, failureCallback);}, failureCallback); }, failureCallback); 典型的回调地狱callback hell示例。在这种情况下多个异步操作依赖于前一个操作的结果导致代码的嵌套层级变得很深从而降低了可读性和可维护性 3.2 使用promise doSomething().then(function(result) {return doSomethingElse(result); }) .then(function(newResult) {return doThirdThing(newResult); }) .then(function(finalResult) {console.log(得到最终结果: finalResult); }) .catch(failureCallback); 链式操作减低了编码难度 代码可读性明显增强 3.3 promise 3.3.1 状态 promise对象仅有三种状态 pending进行中 fulfilled已成功 rejected已失败 3.3.2 特点 对象的状态不受外界影响只有异步操作的结果可以决定当前是哪一种状态 一旦状态改变从pending变为fulfilled和从pending变为rejected就不会再变任何时候都可以得到这个结果 3.3.3 流程 3.3.4 用法 promise为构造函数 const promise new Promise(function(resolve, reject) {}); Promise构造函数接受一个函数作为参数该函数的两个参数分别是resolve和reject resolve函数的作用是将Promise对象的状态从“未完成”变为“成功” reject函数的作用是将Promise对象的状态从“未完成”变为“失败” 3.3.5 实例方法 promise .then() .catch() .finally() Promise对象的错误具有“冒泡”性质会一直向后传递直到被捕获为止 Promise对象抛出的错误不会传递到外层代码即不会有任何反应 finally()方法用于指定不管 Promise 对象最后状态如何都会执行的操作 3.3.6 使用方法 Promise对象抛出的错误不会传递到外层代码即不会有任何反应 const someAsyncThing function() {return new Promise(function(resolve, reject) {// 下面一行会报错因为x没有声明resolve(x 2);}); }; 通过all()实现多个请求合并在一起汇总所有请求结果只需设置一个loading即可 3.3.7 案例 异步插入500w条数据 const {v4: uuidv4} require(uuid); const User require(./models/user) const logger require(../logger/logger) const getRequestData require(./data-generator);/*** 异步插入500w条数据*/(async function ormInsert() {try {await User.sync(); // 确保表结构已创建const batchPromises [];for (let i 0; i 10; i) {batchPromises.push((async () {const dataList getRequestData(25);await User.bulkCreate(dataList, { ignoreDuplicates: true });})());}await Promise.all(batchPromises);} catch (error) {logger.error(Error inserting data:, error);} })() 通过race可以设置图片请求超时 面试官你是怎么理解ES6中 Promise的使用场景 | web前端面试 - 面试官系列 3.4 async/await与promise关系 async/await 和 Promise 是 JavaScript 中用于处理异步操作的两种相关机制。 async 函数始终返回一个 Promise而在 async 函数内部可以使用 await 关键字来等待一个 Promise 完成。 async/await 是对 Promise 的语法糖它使得处理异步操作的代码看起来更像是同步代码 使用 await 关键字可以避免嵌套的回调函数使代码结构更清晰。 // 使用 Promise fetchData().then(data process(data)).then(result display(result)).catch(error handleError(error));// 使用 async/await async function main() {try {const data await fetchData();const result await process(data);display(result);} catch (error) {handleError(error);} }4. axios源码 4.1 简易版axois 4.1.1 axios({}) 构建一个axios构造函数,核心代码为request class Axios {constructor() {}request(config) {return new Promise(resolve {const {url , method get, data {}} config;// 发送ajax请求const xhr new XMLHttpRequest();// XMLHttpRequest的方法,onload为异步,所以设置在send发出之前异步接收成功的结果xhr.open(method, url, true);xhr.onload function() {console.log(xhr.responseText)resolve(xhr.responseText);}xhr.send(data);})} } 导出axios实例 //最终导出的axios方法,即实例的request方法 function CreateAxiosFn(){ let axios new Axios(); //使用bind()方法创建一个新的函数,这个函数是axios.request的绑定版本,这样做的目的是确保在调用req时,this上下文是中指向axios实例 return axios.request.bind(axios) } 4.1.2 axios.method() //定义包含常见HTTP方法的数组get,post...,挂载到Axios原型上 const methodsArr [get,delete,head,options,put,patch,post]; //遍历方法数组 methodArr.forEach(met {Axios.prototype[met] function() {console.log(执行met方法)if([get, delete, head, options].includes(met)){return this.request({method:met;url:arguments[0],...arguments[1] || {} })}else{//post、put、patch 等方法return this.request({method:met,url:arguments[0],data:arguments[1] || {}...arguments[2] || {}})}} }) 4.1.3 this指向 肥肠关键 //最终导出的axios方法,即实例的request方法 function CreateAxiosFn(){ let axios new Axios(); //使用bind()方法创建一个新的函数,这个函数是axios.request的绑定版本,这样做的目的是确保在调用req时,this上下文是中指向axios实例 return axios.request.bind(axios) } then 将Axios.prototype 上的方法搬运到request上 创建工具 const utils { // 定义一个包含工具方法的对象extend(a, b, context) { // 定义 extend 方法接收目标对象 a、源对象 b 和上下文对象 contextfor (let key in b) { // 遍历源对象 b 的所有可枚举属性if (b.hasOwnProperty(key)) { // 确保属性是源对象 b 自身的属性if (typeof b[key] function) { // 判断属性值是否是函数a[key] b[key].bind(context); // 将函数绑定到指定上下文 context并赋值给目标对象 a} else { // 如果属性不是函数a[key] b[key]; // 直接将属性值复制到目标对象 a}}}} };修改导出的方法 function CreateAxiosFn() {let axios new Axios();let req axios.request.bind(axios);// 增加代码utils.extend(req, Axios.prototype, axios)return req; } 4.1.4 构造拦截器 1. 构造函数 class InterceptorsManage { // 定义一个名为 InterceptorsManage 的类constructor() { // 构造函数用于初始化类的实例this.handlers []; // 初始化一个空数组用于存储拦截器处理函数}use(fullfield, rejected) { // 定义 use 方法用于添加新的拦截器this.handlers.push({ // 将新的拦截器对象添加到 handlers 数组中fullfield, // 添加成功处理函数rejected // 添加失败处理函数});} }通过使用数组Axios 能够支持添加多个请求拦截器。这意味着用户可以定义多个函数每个函数可以在请求发送之前处理请求配置。这样设计可以使得不同的拦截器可以分别处理不同的逻辑例如 一个拦截器用于添加授权信息。 另一个拦截器用于记录请求日志。 还有一个拦截器可以用于请求参数的序列化。 2. 实现axios.interceptors.response.use和axios.interceptors.request.use //会在构造函数事,interceptor时初始化一个构造函数 class Axios {constructor() {// 新增代码this.interceptors {request: new InterceptorsManage,response: new InterceptorsManage}}request(config) {...} } 4.1.5 搬到request function CreateAxiosFn() { // 定义一个名为 CreateAxiosFn 的函数let axios new Axios(); // 创建一个 Axios 类的实例并赋值给 axioslet req axios.request.bind(axios); // 绑定 axios 的 request 方法到 req确保 this 指向 axios 实例// 混入方法处理 axios 的 request 方法使之拥有 get、post 等方法utils.extend(req, Axios.prototype, axios); // 将 Axios 原型上的方法混入 req确保可以通过 req 调用这些方法// 新增代码utils.extend(req, axios); // 将 axios 实例的方法和属性混入 req确保 req 也能访问 axios 实例的属性return req; // 返回混合后的 req作为最终的 axios 方法 }4.1.6 拦截器执行顺序 首先将执行ajax的请求封装成一个方法 request(config) {this.sendAjax(config) } sendAjax(config){return new Promise(resolve {const {url , method get, data {}} config;// 发送ajax请求console.log(config);const xhr new XMLHttpRequest();xhr.open(method, url, true);xhr.onload function() {console.log(xhr.responseText)resolve(xhr.responseText);};xhr.send(data);}) } 获得handlers中的回调 request(config) {// 拦截器和请求组装队列let chain [this.sendAjax.bind(this), undefined] // 成对出现的失败回调暂时不处理// 请求拦截this.interceptors.request.handlers.forEach(interceptor {chain.unshift(interceptor.fullfield, interceptor.rejected)})// 响应拦截this.interceptors.response.handlers.forEach(interceptor {chain.push(interceptor.fullfield, interceptor.rejected)})// 执行队列每次执行一对并给promise赋最新的值let promise Promise.resolve(config);while(chain.length 0) {promise promise.then(chain.shift(), chain.shift())}return promise; } 4.2 源码分析 4.2.1 目录 面试官你了解axios的原理吗有看过它的源码吗 | web前端面试 - 面试官系列 5. 权限管理 有空改一下class-select 6. 前端解决跨域 6.1 同源策略 协议相同protocol 主机相同host 端口相同port 6.2 解决方式 6.2.1 JSONP vue中不主要 6.2.2 CORS CORS Cross-Origin Resource Sharing跨域资源共享是一个系统它由一系列传输的HTTP头组成这些HTTP头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应 CORS 实现起来非常方便只需要增加一些 HTTP 头让服务器能声明允许的访问来源 只要后端实现了 CORS就实现了跨域 前端在 HTTP 头配置 CORS 是无效的CORS跨域资源共享Cross-Origin Resource Sharing的机制主要依赖于服务器端的配置。浏览器基于同源策略会自动检查服务器是否允许跨域请求。因此如果后端没有正确配置 CORS前端自己设置 HTTP 头并不能绕过浏览器的跨域限制。 具体来说以下是一些关键的响应头必须由后端设置 Access-Control-Allow-Origin指定允许访问的域名或者使用 * 表示允许所有域名。 Access-Control-Allow-Methods指定允许的 HTTP 方法如 GET、POST、PUT、DELETE 等。 Access-Control-Allow-Headers指定允许的自定义请求头。 Access-Control-Allow-Credentials如果需要发送凭证如 Cookies还需要设置此项为 true。 6.2.3 Proxy 开发环境可以,生产环境不行 无论如何,需要后端配置 7. history模式下有问题404 this 从头创建vue2 项目 1. 步骤 安装vue cli npm install -g vue/cli 创建新项目 vue create yhs-web 选择特性 2. 网络监听 构建工具 1. vue-cli 2. webpack 当你使用命令 vue create my-project 创建一个 Vue 项目时Vue CLI 会自动生成一个项目结构并且会包含默认的 Webpack 配置。这些配置用于开发、构建、打包应用。 2.1 配置 Vue CLI 内部集成了 Webpack 并提供了预配置好的 Webpack 配置。通常在 Vue CLI 项目中你不需要手动修改 Webpack 配置Vue CLI 会在开发和生产模式下自动处理以下内容 处理单文件组件.vue 文件。 处理 JavaScript、CSS、图像等静态资源的打包。 提供热更新Hot Module Replacement, HMR功能来提高开发体验。 通过 webpack-dev-server 提供本地开发服务器。 当你在开发环境下运行 npm run serve 或 yarn serveVue CLI 会 调用 Webpack 配置启动 webpack-dev-server。 Webpack 负责编译、打包代码并在本地服务器上提供应用。 当你在生产环境下运行 npm run build 或 yarn build 时Vue CLI 会 调用 Webpack进行代码的优化和压缩。 将最终的应用程序打包输出到 dist/ 目录中。 可选配置 虽然 Vue CLI 提供了默认的 Webpack 配置但它也允许开发者通过 vue.config.js 文件自定义 Webpack 配置。你可以在 vue.config.js 文件中对 Webpack 进行扩展、修改比如 修改别名alias 添加插件 更改打包规则loaders 2.2 案例 const { defineConfig } require(vue/cli-service) module.exports defineConfig({devServer: {host: 0.0.0.0, // 绑定到所有网络接口port: 8081, // 设置端口号open: false, // 自动打开浏览器},transpileDependencies: true })使用了 defineConfig用于指定 Vue CLI 的配置。 devServer 的配置 host: 0.0.0.0将开发服务器绑定到所有网络接口意味着可以从本地局域网中的其他设备访问该服务器。 port: 8081将开发服务器的端口设置为 8081默认是 8080。 open: false禁用了自动打开浏览器的功能。 const { defineConfig } require(vue/cli-service) module.exports defineConfig({lintOnSave: false,transpileDependencies: true// devServer:{// //devServe在发送请求时,会先走道before指定的函数中进行处理,如果before中没有对应的移动路由,才会请求外网// setupMiddlewares:require(./src/mock/index)// } }) 禁用了 lintOnSave保存时的 ESLint 检查 transpileDependencies 配置为了确保通过 Babel 转译依赖项以提高兼容性。 注释掉了开发服务器的中间件配置可能用于本地模拟数据。 setupMiddlewares 指定了中间件处理函数路径指向 ./src/mock/index这表明项目可能使用了一个本地的模拟数据服务器用来处理请求。如果注释去掉它将通过自定义的中间件处理请求如使用 mock 数据只有当该中间件无法处理请求时才会请求外部 API。 2.3 正确示例 Webpack 需要通过 entry、output、rules 和 plugins 来进行大量配置尤其在处理不同类型的资源如 JS、CSS、图片等时需要加载不同的 loader。 const path require(path); const HtmlWebpackPlugin require(html-webpack-plugin);module.exports {entry: ./src/index.js,output: {filename: bundle.js,path: path.resolve(__dirname, dist),},module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: babel-loader,},{test: /\.css$/,use: [style-loader, css-loader],},],},plugins: [new HtmlWebpackPlugin({template: ./src/index.html,}),],devServer: {contentBase: ./dist,hot: true,}, };3. vite 3.1 与webpack区别 3.1.1 webpack Webpack 是一个基于打包bundling的工具主要通过以下步骤工作 静态分析依赖关系Webpack 从入口文件如 src/index.js开始递归地构建依赖图将项目中所有的模块包括 JS、CSS、图片等都打包成一个或多个文件。 打包和优化Webpack 会将所有依赖打包成少量的文件通常是 bundle.js并应用一些优化策略如代码分割、压缩、Tree Shaking 等。 开发模式和热更新Webpack 开发时会启动 webpack-dev-server它会将代码加载到内存中并支持热模块替换HMR当源代码发生变化时只更新变化的部分模块而不是刷新整个页面 3.1.2 vite Vite 的主要目标是提高开发效率特别是在大型项目中。它采用了一种与 Webpack 不同的工作方式 即时启动Instant Server StartVite 使用原生 ES 模块ESM支持的浏览器来直接加载 JavaScript 文件而不是像 Webpack 一样打包所有文件。它会根据需要按需加载模块而不是一次性打包整个项目。 模块按需编译在开发时Vite 只编译正在使用的模块而不是打包整个项目。这大大减少了启动时间和内存占用。 生产模式下打包在生产环境中Vite 仍然使用 Rollup 进行打包Rollup 和 Webpack 类似是另一种打包工具生成优化后的静态资源文件。 3.2 案例 案例1 import path from path import { fileURLToPath, URL } from urlimport { defineConfig } from vite import vue from vitejs/plugin-vue import { viteSingleFile } from vite-plugin-singlefile // 构建配置会根据process.env.LTB来决定是否构建为库 //LIB值定义在语句build-lib,运行该命令设置lib值自动打包为库 const build process.env.LIB? {lib: {entry: path.resolve(__dirname, src/components/index.ts),name: pev2,fileName: pev2,},rollupOptions: {external: [vue],output: {// Provide global variables to use in the UMD build// Add external deps hereglobals: {vue: Vue,},},},}: {outDir: dist-app,target: esnext,assetsInlineLimit: 100000000,chunkSizeWarningLimit: 100000000,cssCodeSplit: false,brotliSize: false,rollupOptions: {output: {inlineDynamicImports: true,},},}// https://vitejs.dev/config/ export default defineConfig({build: build,plugins: [ //使用了 vue 插件用于支持 Vue 单文件组件。vue({template: {compilerOptions: {whitespace: preserve,},},}), //使用 viteSingleFile 插件将所有资源内联到一个单文件中。viteSingleFile(),], //路径别名resolve: {alias: {: fileURLToPath(new URL(./src, import.meta.url)),},},define: { //定义了 __APP_VERSION__ 来读取 package.json 中的版本号__APP_VERSION__: JSON.stringify(process.env.npm_package_version), //定义了 process.env.NODE_ENV 以便根据环境切换配置。process.env.NODE_ENV: JSON.stringify(process.env.NODE_ENV),}, })根据LIB值决定构建模式 当 process.env.LIB 为 true 时构建为库 lib: entry: 指定库的入口文件为 src/components/index.ts这是库的主要导出文件。 name: 定义库的名称为 pev2这个名称会在 UMDUniversal Module Definition构建中使用。 fileName: 定义输出文件的名称为 pev2。 rollupOptions: external: 指定外部依赖 vue意味着在打包时 Vue 不会被包含在输出文件中而是期望在运行时通过全局变量 Vue 提供。 output : globals: 定义 UMD 构建时的全局变量用于引用外部依赖。在这里vue 被指定为全局变量 Vue这使得使用这个库的应用能够在全局上下文中访问 Vue。 当 process.env.LIB 不存在或为 false 时构建为普通应用 outDir: 指定构建输出目录为 dist-app构建结果会输出到这个目录下。 target: 指定构建目标为 esnext表示构建输出将使用最新的 ECMAScript 语法特性。 assetsInlineLimit: 设置资产内联的限制这里设定为一个非常大的值100000000意味着几乎所有的资源如小于这个大小的图像、CSS 文件等都会被内联。 chunkSizeWarningLimit: 设定 chunk 大小警告的限制设置为一个非常大的值以避免在构建时收到 chunk 大小的警告。 cssCodeSplit: 设置为 false表示禁用 CSS 代码分割所有的 CSS 会被打包成一个文件。 brotliSize: 设置为 false表示不计算 Brotli 压缩的大小。 rollupOptions: output : inlineDynamicImports: 设置为 true表示所有动态导入的模块都将内联到单个输出文件中而不是生成多个分离的 chunk。 构建配置 根据build决定是否构建为库 使用vue插件用于支持vue单文件组件 全局常量 __APP_VERSION__: 这个常量被定义为当前项目的版本号它是从 package.json 文件中读取的 version 字段通过 process.env.npm_package_version。 通过 JSON.stringify 处理后它会转换为一个字符串这样在应用中可以直接引用例如 javascript复制代码 console.log(__APP_VERSION__); // 输出项目的版本号 这对于版本管理、调试和在 UI 中展示版本号很有用。 process.env.NODE_ENV: 这个常量代表当前的运行环境如开发、生产或测试。通常在开发工具链中这个值会被设置为 development 或 production。 通过 JSON.stringify 处理后引用时会是一个字符串。例如 javascript复制代码if (process.env.NODE_ENV production) {// 执行生产环境特定的代码 } 使用 NODE_ENV 变量的好处是可以在代码中根据不同的环境执行不同的逻辑比如启用调试工具、日志记录等。 全局常量 可以配置的地方 vite define 根实例中 // main.js import { createApp } from vue; import App from ./App.vue;const app createApp(App); // 获取版本号 const APP_VERSION process.env.npm_package_version; // 访问环境变量 const NODE_ENV process.env.NODE_ENV || development; // 获取当前环境变量app.provide(appVersion, __APP_VERSION__); app.provide(env, process.env.NODE_ENV);app.mount(#app);组件中可以使用this.appVersion 使用vuex // store.js import { createStore } from vuex;const store createStore({state: {appVersion: __APP_VERSION__,env: process.env.NODE_ENV,}, });export default store;在环境变量文件中设置 # .env VITE_APP_VERSION1.0.0在组件中访问 console.log(import.meta.env.VITE_APP_VERSION); // 访问环境变量案例2 import { fileURLToPath, URL } from node:url ​ import { defineConfig } from vite import vue from vitejs/plugin-vue import AutoImport from unplugin-auto-import/vite import Components from unplugin-vue-components/vite import { ElementPlusResolver } from unplugin-vue-components/resolvers ​ import Icons from unplugin-icons/vite import IconsResolver from unplugin-icons/resolver // https://vitejs.dev/config/ export default defineConfig({plugins: [ //支持vue单文件组件vue(),AutoImport({resolvers: [ElementPlusResolver(),// 自动导入图标组件IconsResolver({prefix: Icon,}),],}),Components({resolvers: [ElementPlusResolver(),// 自动注册图标组件IconsResolver({enabledCollections: [ep],}),],}),Icons({autoInstall: true,}), ​],resolve: {alias: {: fileURLToPath(new URL(./src, import.meta.url)),/ts: ./src/*.ts,/tsDeep: ./src/**/*.ts}} }) ​ 差异 第一个项目使用了 viteSingleFile使其可以将项目打包成一个单文件适合需要在某些特殊场景下进行部署的项目。 第二个项目更加专注于提高开发体验使用了自动导入、组件自动注册和图标插件特别适合使用 Element Plus UI 框架的项目。 全局变量第一个项目有更多针对版本号和环境的全局变量定义而第二个项目没有这方面的配置。 3.3 正确示例 Vite 的配置相对简洁因为 Vite 默认支持现代浏览器的 ESM 规范很多复杂的配置如模块加载、热更新都是开箱即用的开发服务器和打包的配置都很简洁。 import { defineConfig } from vite; import vue from vitejs/plugin-vue; ​ export default defineConfig({plugins: [vue()],server: {host: 0.0.0.0,port: 3000,open: true, // 启动时自动打开浏览器},build: {outDir: dist, // 打包输出目录}, }); ​ TS 1. tsconfig.json配置 GIT 更换仓库 更改远程仓库地址 git remote set-url origin 新地址 git remote set-url origin gitgithub.com:DHWhale01/yhs-web.git https://gitee.com/code-ql/yhs-web.git 正常提交就可以了
http://www.dnsts.com.cn/news/21970.html

相关文章:

  • 网站开发ceil(5.5)如何做企业网站
  • 泰安钢管网站建设centos和wordpress
  • 网站改版301怎么做网站 建设 语言
  • iis网站开发需要哪些配置开广告店需要什么技术
  • 旅游网站模板库河南网站建设培训
  • 一流的网站建设流程wordpress深度开发
  • 织梦通用企业网站模板咸阳网站建设
  • 怎么查看网站虚拟空间辽宁建设工程信息网上开标流程
  • 找别人做网站的注意事项互联网最吃香的职业
  • 做平面那个网站素材好义乌外贸
  • 长沙做模板网站电商设计网站培训
  • 凡科网做的网站怎么样网站设计大全推荐
  • 10元网站备案深圳南山区网站建设公司
  • 网站开发PHP招聘大城网站优化
  • 公司网站制作费做无形资产网络规划与设计课程总结
  • 建设银行网站修改wordpress在本地安装
  • 怎么邀约客户做网站wordpress搜索被攻击
  • 绍兴集团网站建设免费搭建私人网站
  • 网站被k原因人力资源公司网站建设
  • 邢台移动网站建设google权重查询
  • 网站建站平台源码淄博免费网站建设
  • 网站推广的目的是什windows系统wordpress
  • 天猫商城网站风格专业做网站设计
  • 厦门网站建设高级课程wordpress註冊一定要郵箱嗎
  • 在线看mv视频网站入口软件下载wordpress变更域名插件
  • 微网站开发平台 知乎线上商城运营方案
  • 做淘宝客网站流量选择竹溪网站建设
  • 关于网站建设费用wordpress 舆情管理系统
  • 网站假设教程小米应用商店下载
  • 产品推广网站厦门做网站最好的公司