您的位置:首页 > 娱乐 > 八卦 > 电子商城是什么意思_网页数据抓取_百度上怎么发布信息啊_危机公关

电子商城是什么意思_网页数据抓取_百度上怎么发布信息啊_危机公关

2025/2/26 13:07:15 来源:https://blog.csdn.net/Sunshinedada/article/details/145865188  浏览:    关键词:电子商城是什么意思_网页数据抓取_百度上怎么发布信息啊_危机公关
电子商城是什么意思_网页数据抓取_百度上怎么发布信息啊_危机公关

Vue面试题

Vue2.0的生命周期,每个生命周期分别做了哪些事情

  1. create阶段:vue实例被创建。

beforeCreate: 创建前,此时data和methods中的数据都还没有初始化;

created:创建完毕,data中有值,未挂载。

  1. mount阶段: vue实例被挂载到真实DOM节点。

beforeMount:可以发起服务端请求,去请求数据,数据更新时调用;

mounted: 此时可以操作Dom。

  1. update阶段:当vue实例里面的data数据变化时,触发组件的重新渲染。

beforeUpdate: 数据更新时调用;

updated: 数据更新完毕,Dom节点也已经更新

  1. destroy阶段:vue实例被销毁。

beforeDestroy:实例被销毁前,此时可以手动销毁一些方法;

destroyed:完全销毁,所有的东西都会被解绑,事件以及事件监听都会被移除,子实例也会被销毁。

Vue3.0的生命周期

  1. 创建阶段:

setup(): 开始创建组件之前,在beforeCreate和created之前执行。创建的是data和methods。

  1. 挂载阶段:

onBeforeMount() : 组件挂载到节点上之前执行的函数。

onMounted() : 组件挂载完成后执行的函数。

onBeforeUpdate(): 组件更新之前执行的函数。

onUpdated(): 组件更新完成之后执行的函数。

onBeforeUnmount(): 组件卸载之前执行的函数。

onUnmounted(): 组件卸载完成后执行的函数。

onActivated(): 被包含在<keep-alive></keep-alive>中的组件,会多出两个生命周期钩子函数。被激活时执行。

onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。

onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数

keep-alive

作用:实现组件缓存。

keep-alive是vue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。

钩子函数:会在activated和deactivated这两个生命周期中进行数据变更,“activated”组件渲染后调用,
“deactivated”组件销毁后调用。

应用场景:填写表格的时候,假如要填写银行卡号,切出去找号码的时候再回来之前填写的信息都没有了,还需要重新写。加上keep-alive标签,当你访问了一个已经加入缓存的页面,本身的生命周期就不会再执行了,而是去执行新的生命周期,新增了两个生命周期activated和deactivated。

<keep-alive><component></component>
</keep-alive>

可以设置以下属性:include - 字符串或正则表达式,只有名称匹配的组件会被缓存。exclude - 字符串或正则表达式,任何名称匹配的组件都不会被缓存。max - 数字,最多可以缓存多少组件实例。

<keep-alive include="a,b"><component :is="view"></component>
</keep-alive><!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/"><component :is="view"></component>
</keep-alive><!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']"><component :is="view"></component>
</keep-alive>

Vue2和Vue3区别

  1. 生命周期钩子:
    Vue3的生命周期钩子名称以"on"开头,例如onMounted、onUpdated等,而Vue2的钩子没有"on"前缀。Vue3引入了新的生命周期钩子函数,如onBeforeMount和onBeforeUnmount。

  2. 响应式系统(数据监听):
    从数据双向绑定来说,vue2 的双向数据绑定是利⽤Object.definePropert()对数据进⾏劫持 结合 发布订阅模式的⽅式来实现的。vue3 中使⽤了 es6 的Proxy对象来实现响应式系统,通过reactive() 函数给每⼀个对象都包⼀层Proxy,通过Proxy劫持整个对象,并返回一个代理对象。

  3. Composition API:
    Vue3引入了Composition API,这是一种新的方式来组织和复用代码逻辑。它允许开发者将同一逻辑功能的代码写在一起,提高了代码的可读性和可维护性。

  4. 多根节点:
    Vue3支持组件拥有多个根节点,即fragment,而Vue2要求组件只能有一个根节点。

  5. 按需引入:
    Vue2中new出的实例对象,所有的东西都在这个vue对象上,这样其实⽆论你⽤到还是没⽤到,都会跑⼀遍,这样不仅提⾼了性能消耗,也增加了⽤户加载时间。
    ⽽vue3.0中可以⽤ES module imports按需引⼊,不仅我们开发起来更加的便捷,减少了内存消耗,也同时减少了⽤户加载时间,优化⽤户体验。

  6. 性能和体积:
    Vue3在性能上有所提升,并且打包后的体积更小。它支持静态模板渲染,提供了更好的TypeScript支持。

  7. vue3还新增了⼀些内置组件和⽅法。如:keep-alive内置组件等等,还增加了setup函数。

vue经历从2.0到3.0更新之后,变得更轻,更快,使⽤起来更加⽅便,每⼀次的版本迭代都是对上⼀个版本的升级优化,不管 是对于我们开发者还是对于⽤户体验都是不断地在越来越⽅便。

vue3.0中的ref和reactive的区别

ref 和 reactive 都是用来定义响应式数据的 reactive更推荐去定义复杂的数据类型 ref 更推荐定义基本类型。

ref操作数据需要.value,template模板中不需要。reactive都不需要.value

ref虽然定义的是基本数据类型,但是ref也可以定义数组和对象,ref转化数据只有一层,ref只能监听元素本身的变更,而无法监听数组元素数量的更改。而reactive可以监听多层。一般数组用ref,对象用reactive定义。

用 reactive() 创建的响应式对象,整个对象是响应式的。而对象里的每一项都是普通的值 当你把它用展开运算符展开后 整个对象的普通值都不是响应式的。而用 ref() 创建的响应式的值,本身就是响应式的 并不依赖于其他对象。

Vue的通讯方式

组件间的传值方式

  1. 父组件向子组件传值:
    在父组件中调用子组件的标签中使用v-bind进行传值,在子组件中用props进行接收。pros与data同级,里面是一个数组,内容就是自定义属性的名字。

  2. 子组件向父组件传值:
    用的是发布订阅者模式。子组件用this. e m i t ( " 事件名 " ,要传递给父组件的数据 ) , t h i s . emit("事件名",要传递给父组件的数据),this. emit("事件名",要传递给父组件的数据)this.emit发布一个自定义事件,接收俩参数,第一个参数是事件名,第二个参数是要传递的数据。父组件要在调用子组件的标签中用@事件名= "回调函数"触发自定义事件。

  3. 事件车:
    公共事件总线eventBus,实际上就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件之间的通信(任何两个都可以)。Bus. e m i t ( " c l i c k " , d a t a ) 传, B u s . emit("click",data)传,Bus. emit("click",data)传,Bus.on(“click”,target)接收。

  4. Vuex:状态管理工具。值一旦被修改,所有的引用该值的地方都会自动刷新。

五大核心:
①state: 保存数据,相当于data,页面中用this.$store.state来获取定义的数据。

②getters:计算属性,也是依赖于缓存,缓存里面的值发生变化了,才会重新计算。getters方法会接收一个参数,就是state对象。页面中属性名获取用this.$store.getters.getStateCount

③Mutations: 修改state的值的唯一方法。要在methods里面使用,this.$store.commit(“方法名”)

④Actions: (相当于mothous)方法对象的集合。在actions里面提交一个mutations再去修改状态值。

在页面中通过this. s t o r e . d i s p a t h ( " a c t i o n s 里面的方法名 " ) 提交 A c t i o n s ,在 a c t i o n s 通过 a c t i o n s 方法里面的参数名 . c o m m i t ( " c u t a t i o n s 里面的方法名 " ) 。获取用 t h i s . store.dispath("actions里面的方法名")提交Actions,在actions通过actions方法里面的参数名.commit("cutations里面的方法名")。获取用this. store.dispath("actions里面的方法名")提交Actions,在actions通过actions方法里面的参数名.commit("cutations里面的方法名")。获取用this.store.state.count

⑤model模块

  1. 跨组件通讯 a t t r s 、 attrs、 attrslisteners Provide、inject

父组件调用子组件方法,子组件调用父组件的方法

①父组件调用子组件的方法:

在父组件调用子组件的标签中使用ref定义一个标识名。然后在父组件中使用this.$refs.自定义的标识名,可以拿到子组件所以得变量和方法。

②子组件调用父组件的方法:

方法一:在父组件中定义一个方法,在调用子组件的标签中,使用 :定义一个方法名=“要传递的方法”。在子组件中使用props进行接收父组件传来的方法,在点击按钮的时候以函数的时候调用父组件传来的方法。

方法二:在父组件调用子组件的标签中,使用 @自定义方法名=“要传递的方法”,在子组件中使用this.$emit(“传过来的方法名”, 参数1, 参数2)

vue的数据双向绑定

原理:数据劫持结合发布订阅者模式。数据被获取或者修改的时候,会触发监听者对应的回调函数,进行一些逻辑处理。

具体怎么被监听的:vue2.0用object.defineproperty()方法监听的是对象某个属性的获取修改,Vue3.0用的是proxy反向代理,监听的是整个对象属性的修改。

vue的计算属性computed与监听器watch的区别

watch 属性监听 是一个对象,键是需要观察的属性,值是对应回调函数,主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作,监听属性的变化,需要在数据变化时执行异步或开销较大的操作时使用

computed 计算属性 属性的结果会被缓存,当computed中的函数所依赖的属性没有发生改变的时候,那么调用当前函数的时候结果会从缓存中读取。除非依赖的响应式属性变化时才会重新计算,主要当做属性来使用 computed中的函数必须用return返回最终的结果 computed更高效,优先使用。data 不改变,computed 不更新。

使用场景computed:当一个属性受多个属性影响的时候使用,例:计算购物车中总价、计算列表中满足特定条件的元素个数等 watch:当一条数据影响多条数据的时候使用,例:搜索数据

v-if 和 v-for 的优先级

在Vue2.0中,v-for的优先级是高于v-if的
当vue处理指令时,v-for比v-if具有更高的优先级,通过v-if移动到容器元素,不会再重复遍历列表中的每个值,取而代之的是,我们只检查它一次,且不会再v-if为否的时候运行v-for。

而Vue3.0中,v-if的优先级是高于v-for的 (官网上说到这样v-if将没有权限访问到v-for里面的变量),所以Vue3中将不允许v-if和v-for一起使用。

因此我们不推荐v-for和v-if一起使用,可以在v-for的外面新增一个模板标签template,在template上使用v-if。因为如果两者同时出现的话,那每次循环都会执行v-if,会很浪费性能。

v-for中key的作用

  1. key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度,更高效的更新虚拟DOM;

  2. Vue在patch过程中判断两个节点是否是相同节点,key是一个必要条件,渲染一组列表时,key往往是唯一标识,所以如果不定义key的话,Vue只能认为比较的两个节点是同一个,哪怕它们实际上不是,这导致了频繁更新元素,使得整个patch过程比较低效,影响性能;

  3. 从源码中可以知道,Vue判断两个节点是否相同时主要判断两者的key和元素类型等,因此如果不设置key,它的值就是undefined,则可能永 远认为这是两个相同的节点,只能去做更新操作,这造成了大量的dom更新操作,明显是不可取的。

注意:v-for中key一般不以索引作为key值。
假如我们在遍历的数组的最后面加一条数据,那么索引加一,只需要改变一次即可。但是如果我们在数组的第一个加一条数据,那么新加的数据的索引为0,后面所有的数据的索引都会加一都会发生改变,那么需要重新一个一个遍历,所有的算法都要重新来一遍,消耗性能。但是如果key是一个code,通过匹配code,那么无论数据加到哪里,都只改变这一条数据。

虚拟DOM

虚拟DOM就是用JS对象结构表示DOM结构,然后再用这个树构建真正的DOM树放到页面中去,当我们这个虚拟DOM以JS结构的形式存在,计算性能较好,并且由于减少了实际DOM操作的次数,性能会有较大的提升。(Vue就是使用的虚拟DOM)

优点:因为Javascript的运算速度远大于DOM操作的执行速度,因此,运用patching算法来计算出真正需要更新的节点,最大限度地减少DOM操作,从而提高性能。减少了浏览器的回流和重绘。

缺点:首次显示要慢些:首次渲染大量DOM时,由于多了一层虚拟DOM的计算, 会比innerHTML插入慢。

$nextTick

this.$nextTick(()=>{})
  1. nextTick是Vue提供的一个全局API, n e x t T i c k 接收一个函数作为参数,是在下次 D O M 更新循环结束之后执行延迟回调(在下一个时间片执行该函数的方法),或者说在浏览器初次加载或因为某些操作导致 D o m 树渲染,让所有的 D o m 节点加载完毕之后执行的回调。通常用于执行一个方法时, D o m 节点还未加载成功时。在修改数据之后使用 nextTick接收一个函数作为参数,是在下次DOM更新循环结束之后执行延迟回调(在下一个时间片执行该函数的方法),或者说在浏览器初次加载或因为某些操作导致Dom树渲染,让所有的Dom节点加载完毕之后执行的回调。通常用于执行一个方法时,Dom节点还未加载成功时。在修改数据之后使用 nextTick接收一个函数作为参数,是在下次DOM更新循环结束之后执行延迟回调(在下一个时间片执行该函数的方法),或者说在浏览器初次加载或因为某些操作导致Dom树渲染,让所有的Dom节点加载完毕之后执行的回调。通常用于执行一个方法时,Dom节点还未加载成功时。在修改数据之后使用nextTick,则可以在回调中获取更新后的DOM;

  2. Vue在更新DOM时是异步执行的。只要侦听到数据变化,Vue将开启1个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watcher被多次触发,只会被推入到队列中-次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作是非常重要的。nextTick方法会在队列中加入一个回调函数,确保该函数在前面的dom操作完成后才调用;

  3. 比如,我在干什么的时候就会使用nextTick,传一个回调函数进去,在里面执行dom操作即可;

  4. 我也有简单了解nextTick实现,它会在callbacks里面加入我们传入的函数,然后用timerFunc异步方式调用它们,首选的异步方式会是Promise。这让我明白了为什么可以在nextTick中看到dom操作结果。

为什么vue里面的data是个函数呢?

<script>export default {name: 'BtnCount',data () {return {count: 0}}}
</script>
  1. 如果data是一个函数的话,这样每复用一次组件,就会返回一份新的data(类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据)。之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响。

  2. Object是引用数据类型,里面保存的是内存地址,单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。当data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,就不会相互影响。这都是因为js本身的特性带来的,跟vue本身设计无关。
    所以说vue组件的data必须是函数。

vue中常见的事件修饰符

  1. prevent: 阻止默认事件(常用)
changes(e){e.preventDefault()
}
  1. stop:阻止事件冒泡(常用)
<button @click.stop="changes">点我</button>
  1. once:事件只触发一次(常用)
<button @click.once="changes">点我</button>
  1. captrue:使用事件的捕捉模式(不常用)
  2. self:只有event.target是当前操作的元素时才触发事件(不常用)
  3. passive:事件的默认行为立即执行,无需等待事件回调执行完毕(不常用)

例:点击超链接后会弹窗然后跳转到指定的url,那么我们又想阻止冒泡,又想阻止默认行为,该怎么办呢?
可以多个事件修饰符一起使用:@click.prevent.stop,页面上只会弹窗就不跳转了

vue生命周期中,如果发一个异步请求,应该放在哪里?

一般放到created,如果要实现页面加载完之后的操作,就放到mounted里面。
异步:$nextTick以及promise的两种方法。

vue页面跳转

  1. 使用标签创建链接,用户点击后实现页面跳转。
<router-link to = "要跳转的页面地址">--</router-link>
  1. 使用this.$router.push方法在Vue组件内部实现编程式导航。
    可以通过name或者path进行跳转。

两种传参方式,使用params和query进行传参

params主要用于定义动态路由,在路由配置中以:开头定义参数,然后在组件中通过this.$route.params获取。

query主要用于在URL的查询字符串中传递参数,它会将参数附加在URL后面,以?开始,多个参数以&连接,用户可以在地址栏看到参数。在组件中通过this.$route.query获取。

路由模式

  1. history模式
    优点: URL更加美观,不带有#,更接近传统的网站URL

缺点:后期项目上线,需要服务器(nginx或者java环境等)配合处理路径问题,否则刷新会有404。

  1. hash模式
    优点:兼容性更好,因为不需要服务器端处理路径。

缺点:URL带有#不太美观,且SEO优化方面相对较差。

路由守卫

在路由配置文件中使用createRouter创建路由router,通过
router.beforeEach((to, from, next) => {})设置路由守卫,
router.beforeEach接收一个函数作为参数,函数中又有三个参数,分别是to要跳到的页面对象, form从哪个页面跳转, next()方法必须调用一次 。

可以在路由守卫中设置网页标题。还可以进行路由健全,判断用户是否有权限看到页面。在routes.js路由里面添加一个标识isLogin,如果有这个标识,则有权限访问,否则跳转到登录页。

请求拦截和响应拦截

新建一个api文件夹,在文件夹下新建一个config.js文件用来配置请求。使用axios.create创建axios实例对象instance。

请求拦截是instance.interceptors.request.use()。可以在请求拦截中配置请求头里面的参数(在请求头中设置token),以及浏览器中的状态码还有客户端的信息,缓存策略等。

响应拦截是instance.interceptors.response.use()。根据服务器返回的响应报文,根据不同的状态码做出不同的处理。(状态码不是固定的,是前后端商议最后定下的)。

常见的状态码有哪些

200 成功

301 永久重定向(重定向:进入一个页面时,通过一些设置,让他进入到另一个页面)

302 暂时重定向

304 缓存(正在缓存)

404 资源未找到

500 服务器未找到

AJAX实现原理

AJAX就是浏览器提供API,通过JS调用,从而实现通过代码实现请求和响应。

实现原理:

  1. 创建一个XMLHttpRequest
var xhr = new XMLHttpRequest()
  1. open三个参数,分别是get/post , url地址 ,是否异步(true/false)
xhr.open("GET","http://-----",false)
  1. 监听 onreadystatechange,判断readystate属性(五个值,0,1,2,3,4),判断当值为4的时候为成功 readystate == 4 && state == 200
xhr.onreadystatechange = function(){if(xhr.readystate != 4){return}if(xhr.readystate == 4 && xhr.state == 200){console.log(xhr.responseText)}
}
  1. 敲回车,send发送请求
xhr.send()

Ajax的优势:
①减轻了客户端的内存消耗,Ajax的理念是"按需取数据"。
②无刷新更新页面,提高用户体验。
③将一部分的工作量嫁到客户端,减轻服务器压力

ajax嵌套问题

一个请求需要另一个请求返回的结果作为参数时,就是ajax嵌套,会引起回调地狱的问题,上一个ajax报错,下面的都无法执行。解决方法:使用promise来解决回调地狱的问题。

Axios

  1. Axios是一个基于Promise的HTTP库,可以用在浏览器和node.js 中。

  2. Axios有那些特性?
    ①在浏览器中创建 XMLHttpRequests
    ②在node.js则创建http请求
    ③支持Promise API
    ④支持拦截请求和响应
    ⑤转换请求和响应数据
    ⑥取消请求
    ⑦自动转换成JSON数据格式
    ⑧客户端支持防御XSRF

  3. get和post请求
    get请求传参就是拼到url地址后面的,
    而post是放在 request body(请求体)中的。

  4. 常见的请求方式(接口的调用有几种方式?):get请求,post请求,put请求,delete请求

Axios和Ajax的区别

axios是通过Promise实现对ajax技术的一种封装,简单来说就是ajax技术实现了局部数据的刷新,axios实现了对ajax的封装,axios有的ajax都有,ajax有的axios不一定有。

promise

promise是为了解决回调地狱的问题,因为promise里面是异步的,后台请求数据是同步的,互不影响。

首先创建一个promise对象,接收一个函数作为参数,函数里面有两个参数,分别是resolve,reject。

promise内部有三种状态,pengding是初始状态,resolved是成功时候的状态,rejected是失败时候的状态。

promise的方法有.then方法,成功时候调用的方法,返回的依然是一个promise对象。.catch方法失败的时候调用的方法。.all方法,只有所有参数状态都成功时才会调用。.race方法只要一个状态成功,promise.race就会变成roselve。

new Promise((resolve,reject)=>{setTmieout(()=>{console.log("执行完成")resolve("数据")}2000)}).then((data)=>{console.log("resolve",data)}).catch((reson)=>{console.log("reject",reson)})

EventLoop( js的执行机制 )

JS是单线程的,为了防止一个函数执行时间过长阻塞后面的代码,所以会先将同步代码压入执行栈中,依次执行,将异步代码推入异步队列,异步队列又分为宏任务队列和微任务队列,因为宏任务队列的执行时间较长,所以微任务队列要优先于宏任务队列。

微任务队列的代表就是,promise的.then方法,.catch方法,process.nextTick。

宏任务的话就是包括整体代码script,setTimeTout,setInterval

js的执行机制:

先执行主线程代码(js里面从上到下按顺序执行代码的过程),然后执行微任务,再执行宏任务。其中可能会碰到微任务,宏任务嵌套的问题,递归执行,先执行微任务。

promise本身没有特殊性,是主线程代码,本身是一个同步方法,promise的.then和.catch方法是微任务,是异步方法。

同步,异步

同步:在任务队列中,前一个执行完之后,后一个才执行。
异步:在任务队列中,同时执行任务。

token有效期

token有效期通过第三方鉴权服务由后端返回,有效期过期之后退出登录。判断token有效期是否过期。token获取时间,过期时间以及token时长。用token过期时间与token获取时间的时间差与token时长做比较,就可以知道token是否过期。

webpack

webpack是一个前端构建工具。

前端构建工具就是把开发环境的代码转化成运行环境代码。

一般来说,开发环境的代码是为了更好的阅读,而运行环境的代码则是为了能够更快地执行。因此开发环境和运行环境的代码形式也不相同。比如,开发环境的代码,要通过混淆压缩后才能放在线上运行,这样代码体积更小,而且对代码执行也不会有任何影响。一般需要构建工具处理的几种情况:

  1. 代码压缩
    将JS、CSS代码混淆压缩,让代码体积更小,加载更快。

  2. 编译语法

编写CSS时使用Less、Sass,编写JS时使用ES6、TypeScript等,这些标准目前都无法被浏览器兼容,因此需要构建工具编译,例如使用Babel编译ES6语法。

  1. 处理模块化

CSS和JS的模块化语法,目前都无法被浏览器兼容。因此开发环境可以使用既定的模块化语法,但是需要构建工具将模块化语法编译为浏览器可识别形式。例如使用webpack、Rollup等处理JS模块化。

还有其他的构建工具:最早普及使用的是Grunt,后面又出现Gulp。Webpack是目前流行的构建工具,可以说是构建工具的神器,学习成本较高。

常用Loader

raw-loader:加载文件原始内容(utf-8)

file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)

source-map-loader:加载额外的 Source Map 文件,以方便断点调试

svg-inline-loader:将压缩后的 SVG 内容注入代码中

image-loader:加载并且压缩图片文件

json-loader 加载 JSON 文件(默认包含)

babel-loader:把 ES6 转换成 ES5

ts-loader: 将 TypeScript 转换成 JavaScript

awesome-typescript-loader:将 TypeScript 转换成 JavaScript,性能优于 ts-loader

sass-loader:将SCSS/SASS代码转换成CSS

css-loader:加载 CSS,支持模块化、压缩、文件导入等特性

style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS

postcss-loader:扩展 CSS 语法,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀

vue-loader:加载 Vue.js 单文件组件

常用的Plugin

define-plugin:定义环境变量 (Webpack4 之后指定 mode 会自动配置)

ignore-plugin:忽略部分文件

html-webpack-plugin:简化 HTML 文件创建 (依赖于 html-loader)

web-webpack-plugin:可方便地为单页应用输出 HTML,比 html-webpack-plugin 好用

uglifyjs-webpack-plugin:不支持 ES6 压缩 (Webpack4 以前)

terser-webpack-plugin: 支持压缩 ES6 (Webpack4)

webpack-parallel-uglify-plugin: 多进程执行代码压缩,提升构建速度

mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载 (替代extract-text-webpack-plugin)

serviceworker-webpack-plugin:为网页应用增加离线缓存功能

clean-webpack-plugin: 目录清理

Loader 和 plugin 的区别

Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。

Plugin 就是插件,基于事件流框架 Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

Loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。

Plugin 在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入

vuex和pinia区别

状态管理工具

常用的git命令

常用命令

  1. git clone
  2. git branch 查看本地分支
  3. git branch -a 查看远程分支
  4. git branch -d xxx 删除分支
  5. git add . 暂存到本地
  6. git commit -m “信息备注” 提交信息
  7. git pull 拉取代码
  8. git push 提交代码
  9. git checkout xxx 切换分支
  10. git checkout -b xxx 新建分支并且切换到改分支
  11. git branch -m 旧分支名 新分支名 分支重命名
  12. git status 查看修改的文件
  13. git merge 合并分支
  14. git checkout -b xxx origin/xxx 拉去远程分支
  15. git log 查看提交记录

运用:

  1. 切换到新的分支:
    git branch -a
    git pull
    git checkout --track origin/分支名

  2. 一个分支上的代码修改了,怎么同步到另外一个正在开发的分支上。
    如修改了master分支上的代码,正在开发的dev分支也想拉取修改的master分支
    git checkout master
    git branch -a
    git add .
    git commit -m " "
    git pull
    git push origin master
    //然后合并到dev分支上
    git checkout dev
    git pull
    git merge master
    git push origin dev

  3. 把当前分支的代码推到指定的分支上
    git add .
    git commit -m " "
    git pull
    git push origin 现分支:要推到的分支

  4. 解决git 冲突
    ①git stash 暂存本地代码
    ②git pull 代码重新拉取
    ③git stash pop 合并冲突代码,git 会将冲突代码展示出来
    ④手动合并冲突

let const var 它们之间有什么区别?

  1. var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。 let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。 const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,且不能修改。
  2. var可以先使用,后声明,因为存在变量提升;let必须先声明后使用。
  3. var是允许在相同作用域内重复声明同一个变量的,而let与const不允许这一现象。
  4. let和const会产生暂时性死区

箭头函数和普通函数有哪些区别?

  1. 写法不一样,
  2. 箭头函数不能给别人this指向,普通函数可以修改它的this指向
  3. 箭头函数没有augments参数,普通函数有
  4. 箭头函数不能用作构造函数,普通函数可以用作构造函数

说一下async和await

https://blog.csdn.net/song854601134/article/details/124711956

torefs和toref有用过吗

ref和$refs

项目数据量是多少,有做过实时更新数据吗,怎么实现的

回答自己公司的项目,数据量不大即可。

①Vue2可以监听数组吗 ,②可以监听对象吗?


Vue2可以通过 v-for指令来渲染数组中的数据,并且可以利用 Vue 的响应式系统来监听数组的变化。

Vue2使用了 Object.defineProperty 来实现数据的响应式,但是这个 API 不能检测到数组索引的变化、长度的变化,以及通过索引直接设置数组项的操作。

为了监听这些数组的变化,Vue 提供了一些方法,比如 vm.$set 或者使用原生的数组方法,如 push、pop、shift、unshift、splice、sort、reverse,这些方法会触发视图更新。

如:

<template><div><ul><li v-for="(item, index) in items" :key="index">{{ item }}</li></ul><button @click="addItem">Add Item</button></div>
</template><script>
export default {data() {return {items: ['Apple', 'Banana', 'Cherry']};},methods: {addItem() {this.items.push('Date'); // 使用 Vue 推荐的方法,这将触发视图更新}}
};
</script>

②Vue2可以监听对象,可以使用watch等方法监听对象

插槽怎么用的?

前端部署怎么做的?自己有没有部署过?

前端打包使用npm run build命令打包,然后使用jenkins自动化部署。(公司自动化部署,不需要手动部署)

vue2如果进行数据处理会放到哪个声明周期里面?

在Vue 2中,如果你需要在组件创建或更新之前发起数据请求,通常会将这些请求放在created或mounted生命周期钩子中。

created钩子在组件实例创建后被调用,此时组件已经经过了数据观测 (data observer) 的设置,但DOM还未生成,
而mounted钩子在组件被挂载之后调用,此时DOM已经生成。

操作Dom可以在哪个声明周期里面进行

在Vue中,操作DOM通常是在组件的mounted生命周期钩子中进行的,因为此时组件已经被挂载到页面上,所以可以访问到DOM元素。
如果需要在数据更新后重新渲染DOM,则可以在updated生命周期钩子中进行操作。

项目后端有哪些语言开发的?接口怎么管理的?以什么形式给你的接口文档?接口文档里面都会有什么?

Java, 后端会输出一个接口文档给到前端。接口里面会有请求的接口地址,还有需要传的参数以及接口返回的字段。

浏览器的存储方式

浏览器的存储方式主要分为cookie、localStorage和sessionStorage(web Storage)。

浏览器三种存储方式的相同点:

共同点: 都是保存在浏览器端、仅同源可用的本地存储方式

浏览器三种存储方式的不同点(web storage和cookie的区别):

  1. 从存储数据的大小来说:cookie数据不能超过4K,sessionStorage和localStorage可以达到5M。
  2. 从存储数据的种类来说:web storage存储的数据可以是JSON对象,也可以是字符串,而cookie只能是字符串。
  3. 从存储数据的有效期来说:sessionStorage关闭浏览器窗口就删除了,localStorage是永久存储,只有主动删除才会删除掉,cookie必须设置有效期,有效期到了就删除,也可以主动删除。
  4. 从存储数据的作用域来说:sessionStorage作用于本窗口,localstorage和cookie作用于所有的同源页面(同源:协议名,域名,端口名都相同)。
  5. 语义化方法:web storage语义化更强。

现在主要用的是什么框架?

Vue2.0和Vue3.0

父组件和子组件生命周期的优先级

结果:父-创建 —> 父-挂载前 —> 子-创建 —> 子-挂载前 —> 子-挂载完毕 —> 父-挂载完毕

父组件中点击卸载子组件:父-更新前 --> 子-卸载前 --> 子-卸载完毕 --> 更新完毕

公司开发是几个人,项目用的什么技术栈

前端三个个,后端四个。
技术栈:Vue + Vue-cli + Vue-router + Vuex + Axios + Antdesign + Echars

深拷贝和浅拷贝

https://blog.csdn.net/Sunshinedada/article/details/130751257?spm=1001.2014.3001.5501

vue中怎么实现路由的重定向呢

在路由中设置redirect()进行路由的重定向

路由守卫的三种方式

路由和路由器

vue属于SPA(单页面)应用,最终只有一个.html文件显示,那么要实现多个页面的切换,就需要路由。

点击不同的导航项,展示区展示不同的内容
点击导航区,路径发生变化,路径的变化引起了路由器的监听,routes.js中配置路径,指定路由规则(/home/routerView1/helloOne, home/routerView2/helloTwo。即什么路径对应什么组件),从而改变路由的显示,展示不同的组件

路由模式

1. history模式

优点: URL更加美观,不带有#,更接近传统的网站URL

缺点:后期项目上线,需要服务器(nginx或者java环境等)配合处理路径问题,否则刷新会有404。

在router文件夹下的index.js文件中,设置路由模式

// hash模式:createWebHashHistory,history模式:createWebHistory
import {createRouter,createWebHistory
} from "vue-router";
// 引入路由文件
import routes from './routes'// 创建路由
const router = createRouter({// 使用history模式(还有哈希模式)history: createWebHistory(),// 将路由文件注册到vue实例对象上routes// mode: 'history',// base: process.env.BASE_URL,// routes
});

2. hash模式

优点:兼容性更好,因为不需要服务器端处理路径。

缺点:URL带有#不太美观,且SEO优化方面相对较差。

import {createRouter,createWebHashHistory
} from "vue-router";
// hash模式:createWebHashHistory,history模式:createWebHistory
// 引入路由文件
import routes from './routes'// 创建路由
const router = createRouter({// 使用哈希模式(还有history模式)history: createWebHashHistory(),// 将路由文件注册到vue实例对象上routes// mode: 'history',// base: process.env.BASE_URL,// routes
});

一般面向用户的系统使用history模式,后台管理系统可以使用hash模式。

路由跳转

点击详情按钮,跳转到详情页面

跳转页面传参以及接收参数

跳转页面传参 listMessage.js:

传参的时候引用的是useRouter

// 引入
import { useRouter } from 'vue-router';
// 路由
const router = useRouter();
// 详情跳转页面
const detailList = (column, record, index) => {console.log(column, record, index, "跳转");router.push({name: 'listMessageDetailName',params: {id: record.key,number: record.number},query: {type: "2"}})
}

使用params进行传参的时候,路由routes.js文件中,要在path里面同时拼上参数名

children: [{path: 'listMessageDetail/:id/:number',name: "listMessageDetailName",meta: {title: "详情",isShowMenu: true,isLogin: false},component: () =>import('../view/listMessage/src/detail/detail.vue'),},
],

详情页面接收参数 detail.vue:

接收参数的时候引用的是useRoute

<template><div class="detail">{{ id }}-{{ number }}-{{ type }}</div>
</template>
<script setup name="detail">
import { ref } from "vue";
// useRoute
import { useRoute } from "vue-router";
// 定义route
const route = useRoute();
console.log(route,"11111111");
// 获取通过params传来的值
let id = ref("");
let number = ref("");
id.value = route.params.id;
number.value = route.params.number;
console.log(id.value, number.value); // 1  No 1// 获取通过query传来的值
let type = ref("");
type.value = route.query.type;
console.log(type.value,"3333333"); // 2</script><style scoped lang="less">
.detail {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

Vue2组件之间的通信

父组件向子组件传值

将父组件的数据msg和comments传到子组件中

父组件APP.vue:

父组件向子组件传值,父组件在使用子组件的标签中,使用v-bind变量名来接收要传的变量值。

<template><div id="app"><!-- 3. 使用组件 --><List :msg="msg" :comments="comments"/></div>
</template><script>
// 1. 引入子组件
import List from "./components/List.vue";
export default {name: "App",data() {return {msg: "hello",comments: [{name: "BOB",content: "Vue还不错",},{name: "Cat",content: "Vue So Easy",},{name: "BZ",content: "Vue Just So So",},],};},// 2. 注册components: {List,},
};
</script>
<style>
</style>

子组件List.vue:

子组件使用props进行接收父组件传过来的属性,接收的这个属性会成为组件对象的属性。
props与data同级,可以是一个数组,如果传过来的是一个对象,也可以以对象的形式进行接收。

<template><div id="List"><p>{{msg}}</p><ul class="list-group"><li class="list-group-item" v-for="(comment, index) in comments" :key="index"><p>{{comment.name}}</p><p>{{comment.content}}</p></li></ul></div>
</template><script>
export default {name: "List",// 可以直接使用数组接收一个变量// props: ["msg"],// 也可以接收指定的属性名和属性值的类型props: {// 定义一个变量接收,值是类型msg: String,// comments: Array,// 相当于comments: {type: Array,default: ()=>{return {}}},}data() {return {};},
};
</script>
<style>
</style>

子组件向父组件进行传值以及传递方法

父组件APP.vue:

<template><div id="app"><!-- 3. 使用组件 --><!-- 在父组件中添加一个ref属性,定义一个ref值为listComment --><List ref="listComment"/></div>
</template><script>
// 1. 引入子组件
import List from "./components/List.vue";
export default {name: "App",data() {return {msg: "hello",};},mounted(){// 使用this.$refs.标签中定义的ref值,可以得到子组件中所有的信息// 找个触发时机打印一下console.log(this.$refs.listComment); // 得到整个list.vue子组件的整个文件对象,包括子组件中所有的方法和属性(使用时,.方法 .属性即可)},// 2. 注册components: {List,},
};
</script>
<style>
</style>

子组件调用父组件的方法

还可以用过v-bind进行传递,以方法的形式调用

父组件App.vue

在父组件中定义一个方法,在调用子组件的标签中,使用 :定义一个方法名=“要传递的方法”

<template><div id="app"><!-- 3. 使用组件 --><!-- 方法一  :定义一个方法名="要传递的方法" 向子组件传递一个deleteComment方法 --><!-- 方法二:@自定义方法名="要传递的方法"  --><List :comments="comments" :deleteComment="deleteComment" @types="aaa"/></div>
</template><script>
// 1. 引入
import List from "./components/List.vue";
export default {name: "App",data(){return {comments: [{name: "BOB",content: "Vue还不错"},{name: "Cat",content: "Vue So Easy"},{name: "BZ",content: "Vue Just So So"},]}},// 数据在哪个组件,更新数据的行为(处理数据)就应该在哪个组件methods: {// 删除指定下标的评论deleteComment(index){this.comments.splice(index, 1);}aaa(a, b){console.log(a, b,"11111111");}},// 2. 注册components: {List},
};
</script><style>
</style>

子组件List.vue

子组件中使用props进行接收父组件传来的方法,在点击按钮的时候以函数的时候调用父组件传来的方法

<template><div class="List"><ul class="list-group"><li class="list-group-item" v-for="(comment, index) in comments" :key="index"><div class="handle"><a href="javascript:;" @click="deleteItem(comment, index)">删除</a></div><p class="user"><span>{{comment.name}}</span><span>说:</span></p><p class="centence">{{comment.content}}</p></li></ul></div>
</template><script>
export default {name: "List",// 子组件接收父组件的值// 需要声明接收属性 使用props进行接收// 这个属性会成为组件对象的属性// props: ["msg"],// 也可以接收指定的属性名和属性值的类型props: {comments: {type: Array,default: ()=>{return {}}},// 接收父组件传来的删除方法deleteComment: {typeof: Function,required: true}},data() {return {type: 1};},methods: {// 点击列表中的删除按钮deleteItem(comment, index) {if(window.confirm(`确定删除${comment.name}的评论吗`)){// 函数的形式调用父组件的方法this.deleteComment(index);// 方法二 子组件调用父组件的方法还可以使用this.$emit("传过来的方法名", 参数1, 参数2)// 发布订阅this.$emit('types', this.type, true)}}// }
};
</script><style scoped>
</style>

Vue3组件之间的通信

props (父–>子)

在父组件调用子组件的标签中使用v-bind进行传值(固定值直接写到标签内即可),
在子组件中使用defineProps([])进行接收。

父组件:

<template><div><h1>我是父组件</h1><hr/><child :name="name" age = "12"></child></div>
</template>
<script setup>import child from './components/child/child.vue'import { ref } from 'vue'const name = ref('父亲名字')
</script><style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件:

<template><div><h1>我是子组件</h1><p>我收到了父组件的数据:{{ name }}</p><p>{{ props.age }}</p></div>
</template>
<script setup>
const props = defineProps(["name", "age"]);
</script>
<style scoped lang="less">
</style>

自定义事件(子–>父)

父组件:

<template><div><h1>我是父组件</h1><p>父组件显示值 : {{ msg }}</p><hr/><child @childValue="getChildValue"></child></div>
</template><script setup>
import child from './components/child/child.vue'
import {  ref } from 'vue'
let msg = ref('父组件初始值');
const getChildValue = function(message){msg.value = message
}
</script><style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件:

<template><div><h1>我是子组件</h1><button @click="toFather">点击传给父组件</button></div>
</template>
<script setup>
let $emit = defineEmits(['childValue'])
const toFather = function(){$emit('childValue', '我是子组件的值')
}
</script>
<style scoped lang="less">
</style>

defineEmits([‘childValue’])定义了子组件可以触发的一个名为childValue的事件,通过$emit(‘childValue’,‘数据’)触发toFather事件,将参数:‘数据’传给父组件;父组件使用自定义事件@childValue="getChildValue"来接受子组件传来的’数据’。

ref与$parent(父–>子、子–>父)

当父组件渲染时,子组件可能还没有完成加载和渲染。因此,在父组件中直接获取子组件的数据时,子组件可能还没有准备好数据,导致获取到的是旧的数据或者undefined。例如刚开始money显示的是undefined(数据更改,视图没有更改)。想要拿到组件数据前提是该组件将数据暴露出去。

ref:父–>子

子组件中使用defineExpose({})将数据暴露出去,父组件中使用ref定义一个变量可拿到子组件中的数据。

父组件:

<template><div><h1>我是父组件</h1><p>原来的生活费是{{ money }}</p><button @click ="addmoney">点我给儿子涨生活费</button><hr/><child ref="mychildref"></child></div>
</template>
<script setup>
import {ref} from 'vue'
import child from './components/child/child.vue'
const mychildref = ref()
const money = ref()
const addmoney=function(){// console.log(mychildref.value,"**********")money.value = mychildref.value.moneymychildref.value.money  += 200
}
</script>
<style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件:

<template><div><h1>我是子组件</h1><p>我今年{{ age }}岁</p><p>我的生活费{{ money }}</p></div>
</template>
<script setup>
import { ref } from 'vue';
const age = ref(12)
const money = ref(200)
defineExpose({age,money
})
</script>
<style scoped lang="less">
</style>

$parent:子–>父

在父组件中使用defineExpose({})将数据暴露出去,在子组件中定义方法,接收一=一个$parent参数即可拿到父组件的值

父组件:

<template><div><h1>我是父组件</h1><p>我的财产:{{ money }}</p><hr/><child ></child></div>
</template>
<script setup>
import {ref} from 'vue'
import child from './components/child/child.vue'
const money = ref(122000)
defineExpose({money
})
</script>
<style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件:

<template><div><h1>我是子组件</h1><p>父亲原来的钱{{ money1 }}</p><button @click="sayborder($parent)">点我花掉父亲100块</button></div>
</template>
<script setup>
import { ref } from 'vue';
const money1 = ref()
const sayborder =function($parent){money1.value = $parent.money$parent.money-=100
}
</script>
<style scoped lang="less">
</style>

provide与inject(爷–>孙)

使用provide和inject方法实现爷爷组件和孙子组件通信时,孙子组件修改接收到的数据会影响爷爷组件的数据,这是因为provide和inject是基于Vue的响应式系统实现的。

当爷爷组件通过provide将数据传递给后代组件时,这些数据会被Vue的响应式系统进行跟踪。当孙子组件通过inject接收到这些数据时,它们实际上是响应式的,即它们与爷爷组件中的数据建立了引用关系。

因此,当孙子组件修改接收到的数据时,实际上是直接修改了爷爷组件中的数据,这就导致了爷爷组件的数据也会发生变化。

这种影响是由于provide和inject的特性决定的,它们提供了一种方便的方式来在组件之间共享数据,但也需要注意数据的修改可能会影响到其他组件。

祖先组件:

<template><div><h1>我是爷爷组件</h1><p>爷爷给孙子红包{{ money }}</p><child></child></div>
</template>
<script setup>
import child from './components/child/child.vue'
import { provide,ref } from 'vue';
const money = ref('1000')
provide('hongbao',money)
</script>
<style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

后代组件:

<template><div><h1>我是孙子组件</h1><p>我爷爷给我红包{{ money }}</p><button @click="sayborder">点我看看剩多少钱</button></div>
</template>
<script setup>
import { inject,ref } from 'vue';
let money = ref(inject('hongbao'))
const sayborder = function(){money.value= 500
}
</script>
<style scoped lang="less">
</style>

mitt全局事件总线或者叫事件车(兄弟间)

安装mitt

npm i mitt

在utils文件创建mitt.js文件

import mitt from 'mitt'
const $bus = mitt()
export default $bus

在两个子组件都引入mitt文件

组件1:

<template><div><h1>我是子组件1</h1><p>我收到了来自兄弟的信息:{{ message}}</p></div>
</template>
<script setup>import $bus from '../utils/mitt';import {ref} from 'vue'let message =  ref('还不知道呢')$bus.on('mimi',(msg:any)=>{message.value = msg})
</script>

组件2:

<template><div><h1>我是子组件2</h1><button @click="sayborder">点我给兄弟发秘密</button></div>
</template>
<script setup>import $bus from '../utils/mitt';const sayborder = function(){$bus.emit('mimi',{mimi:"遗产全都给我了"})}
</script>

useAttrs(父–>子)

父组件:

<template><div><h1>我是父组件</h1><hr/><child :money = money></child></div>
</template>
<script setup>
import {ref} from 'vue'
import child from './components/child/child.vue'
const money = ref(122000)
</script><style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件:

<template><div><h1>我是子组件</h1><p>收到了父亲的财产{{ money }}</p></div>
</template>
<script setup>
import { useAttrs} from 'vue';
let $arrts = useAttrs()
let {money} = $arrts
</script>
<style scoped lang="less">
</style>

pinia 状态管理工具

安装pinia:

npm i pinia -S

在入口文件main.js中引入

//main.js
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
//选项式
import {defineStore} from 'pinia'
let useInfoStore = defineStore('info',{state:()=>{return {money:1000}},actions:{handle(){this.money +=100}},getter:{}
})
export default useInfoStore
//组合式
import {defineStore} from 'pinia'
import {ref} from 'vue'
let useCountStore = defineStore('Count',()=>{let count = ref(100)let countAdd = function(){count.value +=100}return { count,countAdd}
})
export default useCountStore

组件中使用:

<template><div><p>我在pinia的财产:{{ money }}</p><button @click="add">点我money加100</button></div>
</template>
<script setup>
import useInfoStore from '../store/user'
const info = useInfoStore()
const money = info.money
const add = function(){info.handle()
}
</script>

slot插槽

默认插槽

父组件:

<template><div><h1>我是父组件</h1><hr><child ><div><h1>我是solt传的</h1></div></child></div>
</template>
<script setup>
import child from './components/child/child.vue'
</script>
<style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件

<template><div><h1>我是子组件</h1><slot></slot><button >点我</button></div>
</template>
<script setup>
</script>
<style scoped lang="less">
</style>

具名插槽

父组件:

<template><div><h1>我是父组件</h1><hr><child ><template v-slot:abc><div><h1>我是名字‘abc’solt传的</h1></div></template><!-- v-slot:可以简写成# --><template #bbb><div><h1>我是名字‘bbb’solt传的</h1></div></template></child></div>
</template>
<script setup>
import child from './components/child/child.vue'
</script>
<style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件:

<template><div><h1>我是子组件</h1><slot name="abc"></slot><button >点我</button><slot name="bbb"></slot></div>
</template>
<script setup>
</script>
<style scoped lang="less">
</style>

Pinia 和 Vuex

https://mp.weixin.qq.com/s?__biz=MzA5MTI0ODUzNQ==&mid=2652957572&idx=1&sn=c77f7ca8550aace7714b26d6781ccca3

父组件调用子组件的方法

子组件中使用defineExpose来暴露子组件的方法,这样父组件才能通过ref获取到这些方法并调用。

父组件通过ref属性引用子组件,并在callChildMethod方法中调用了子组件暴露的childMethod。

父组件:

<template><ChildComponent ref="childValue" /><button @click="callChildMethod">Call Child Method</button>
</template><script setup>
import { ref } from 'vue';
import ChildComponent from './components/child/child.vue';const childValue = ref(null);const callChildMethod = () => {if (childValue.value) {// console.log(childValue.value,"(((((((())))))))")childValue.value.childMethod();}
};
</script>
<style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件:

<template><div>子组件</div>
</template>
<script setup>
import { ref, defineExpose } from 'vue';
let names = ref("1111")
const childMethod = () => {console.log('子组件的方法');
};
defineExpose({names,childMethod
});
</script>
<style scoped lang="less">
</style>

子组件调用父组件的方法

父组件在调用子组件时使用v-bind,子组件通过props传递父组件的方法

父组件:

<template><ChildComponent :parentMethod="parentMethod" />
</template><script setup>
import { defineComponent } from 'vue';
import ChildComponent from './components/child/child.vue';const parentMethod = () => {console.log('这是父组件的方法');
};
</script>
<style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件:

<template><button @click="parentMethod">Call Parent Method</button>
</template><script setup>
import { defineProps } from 'vue';const props = defineProps({parentMethod: Function
});
</script>
<style scoped lang="less">
</style>

或者子组件:

<template><button @click="onSubmit">Call Parent Method</button>
</template><script setup>
import { defineProps } from 'vue';const props = defineProps({parentMethod: Function
});
function onSubmit() {props.parentMethod()
}
</script>
<style scoped lang="less">
</style>

方法二:

使用$emit

父组件:

<template><ChildComponent @call-parent-method="parentMethod" />
</template><script setup>
import { defineComponent } from 'vue';
import ChildComponent from './components/child/child.vue';const parentMethod = () => {console.log('This is a parent method');
};
</script>
<style scoped lang="less">
.test8 {width: 100%;height: 100%;background-color: #fff;box-sizing: border-box;padding: 20px;
}
</style>

子组件:

<template><button @click="$emit('call-parent-method')">Call Parent Method</button>
</template><script setup>
import { defineComponent, defineEmits } from 'vue';const emit = defineEmits(['call-parent-method']);
</script>
<style scoped lang="less">
</style>

或者子组件:

<template><button @click="onSubmit">Call Parent Method</button>
</template><script setup>
import { defineComponent, defineEmits } from 'vue';const emit = defineEmits(['call-parent-method']);
function onSubmit() {emit('call-parent-method');
}
</script>
<style scoped lang="less">
</style>

常见的遍历方式

<script setup name="test6">
import {ref, computed} from 'vue'
let data = ref([{type: 'test1',name: 'abc',num: 1},{type: 'test2',name: 'cde',num: 2},{type: 'test1',name: 'fgh',num: 3},
])
//find() 返回符合条件的第一个对象,找不到返回undefined
console.log(data.value.find(item=>item.type=="test"),"111"); // undefined 
console.log(data.value.find(item=>item.type=="test1"),"222"); // {type: 'test1', name: 'abc'} // filter()筛选数组中满足条件的元素,返回筛选后的新数组。如果没有元素满足,则返回一个空数组。
console.log(data.value.filter(item=>item.type=="test1"),"333"); // [{type: 'test1', name: 'abc'},{type: 'test1', name: 'abc'}]
console.log(data.value.filter(item=>item.type=="test"),"444"); // []// map()映射, 遍历数组,返回处理后的新数组。(按照原数组元素顺序依次处理)
let newArray = data.value.map(item=>{return item.num += 1;
});
console.log(newArray,"555"); // [2, 3, 4]// every 判断数组中每一个元素是否符合某个条件,返回一个布尔值。
let array1 = data.value.every(item=>{return item.type=="test1";
});
console.log(array1,"666"); // false// some判断数组中是否有元素符合某个条件,返回一个布尔值。
let array2 = data.value.some(item=>{return item.type=="test1";
});
console.log(array2,"666"); // true
</script>

Axios

Axios是基于Promise的,对原生js中ajax二次封装的网络请求库。(Vue中请求数据使用Axios)

Axios官网:
https://www.axios-http.cn/docs/api_intro

或者
http://www.axios-js.com/

1. 下载Axios

使用nmp下载到生产环境
npm install axios -S

2. 在src文件夹下面新建一个api文件夹

src文件夹下手动新建一个api文件夹,用于对axios的使用,封装数据请求

再在src文件夹–>api文件夹下面新建一个config.js文件和htpp.js文件

config.js文件

  1. config.js文件中先要引入axios对象,

  2. 然后使用axios.create去创建axios实例对象,在这个实例对象中进行axios的常用配置,比如向服务器发送的请求地址,请求超时时间,请求头的参数设置


// 引入axios对象
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
// 创建axios实例对象,参数是axios常用配置4、
const instance = axios.create({// 请求地址// baseURL: 'http://220.249.101.248:37086',baseURL: 'https://local.vrmaker.vip:37086',// 请求超时时间timeout: 60000,// 设置请求头参数headers: {'Content-Type': 'application/json',},
});
  1. 给创建的axios实例对象添加请求拦截器

请求拦截的请求配置有很多,config是请求配置对象,包括请求头里面的参数,以及浏览器中的状态码还有客户端的信息,缓存策略等,我们可以对其进行配置。

具体看https://www.axios-http.cn/docs/api_intro文档中–>请求配置

如果我们在项目的请求拦截中没有设置有些属性,会默认使用文档中的请求配置的默认值

使用:instance.interceptors.request.use()

// 请求拦截
instance.interceptors.request.use(// config 请求配置对象,包括请求头里面的参数,以及浏览器中的状态码还有客户端的信息,缓存策略等(config) => {// 在请求头中设置tokenconfig.headers['Authorization'] = 'VrMakerToken';return config;},// 请求错误时,或者axios代码报错时(error) => {return Promise.reject(error);}
);
  1. 给创建的axios实例对象添加响应拦截器

响应拦截,response是服务器返回的响应报文,
可以在响应拦截中根据与后端约定好的状态码进行不同结果返回。

使用:instance.interceptors.response.use()

常见的htpp协议的状态码有:200 成功301 永久重定向(重定向:进入一个页面时,通过一些设置,让他进入到另一个页面)302 暂时重定向304 缓存(正在缓存)404 资源未找到500 服务器未找到

具体返回信息看https://www.axios-http.cn/docs/api_intro文档中–>响应结构

// 响应拦截
instance.interceptors.response.use(//response 服务器返回的响应报文(response) => {// console.log(response?.data);// console.log(response?.data?.errMsg);// console.log(response?.data?.code === 200)// if(response?.data?.code !== 200){//    return Promise.reject(response?.data?.errMsg ? response?.data?.errMsg : "接口异常");// } return response.data;},// 请求错误时,或者axios代码报错时(error) => {return Promise.reject(error);}
);
  1. 导出axios实例对象
export default instance;

htpp.js文件

config.js文件配置完毕,打开新建的http.js文件,主要对get请求和post请求进行二次封装

  1. 引入axios和config.js文件
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import instance from "./config";
  1. 对axios实例对象的get方法和post方法进行二次封装

get请求的参数是直接拼到请求地址后面的。

我们在https://www.axios-http.cn/docs/api_intro文档中–>请求配置 中可以看到,配置对象中中有url属性,是用于我们传接口url的,params属性是用于传参的,直接会拼到地址栏后面

const get = (url, params)=>{// axios的实例instance会有一个get方法进行二次封装return instance.get(url, {params: params // 传参,是一个对象});
}

或者直接只有一个url参数,调用的时候直接把参数拼到url后面一起传过来请求

const get = (url)=>{// axios的实例instance会有一个get方法进行二次封装return instance.get(url);
}

post请求,三个参数,第一个参数,接口url地址,第二个参数,要传的参数,
第三个参数,config请求配置对象,可传可不传,有特殊的可以覆盖前面config.js文件中
的instance配置。

https://www.axios-http.cn/docs/api_intro文档中–>请求配置

const post = (url, data, config)=>{// axios的实例instance会有一个post方法进行二次封装// config配置文件,可不传,默认会使用axios内部的配置,可以使用第三个参数覆盖config.js里面的instance配置// https://www.axios-http.cn/docs/req_config-->请求配置return instance.post(url, data, config);
}
  1. 导出get和post
export {get,post
}

请求封装完毕

页面中使用get和post请求数据

  1. 页面需要使用时,先引用get和post请求
import {get, post} from "http.js" 
  1. 使用
// get请求使用
get("http://www.baidu.com",{name:111})// post请求使用
post("http://www.baidu.com",{name:111})

具体文件

config.js文件:


// 引入axios对象
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
// 创建axios实例对象,参数是axios常用配置
const instance = axios.create({// 请求地址// baseURL: 'http://220.249.101.248:37086',baseURL: 'https://local.vrmaker.vip:37086',// 请求超时时间timeout: 60000,// 设置请求头参数headers: {'Content-Type': 'application/json',},
});
// 请求拦截
instance.interceptors.request.use(// config 请求配置对象,包括请求头里面的参数,以及浏览器中的状态码还有客户端的信息,缓存策略等(config) => {// 在请求头中设置tokenconfig.headers['Authorization'] = 'VrMakerToken';return config;},// 请求错误时,或者axios代码报错时(error) => {return Promise.reject(error);}
);
// 响应拦截
instance.interceptors.response.use(//response 服务器返回的响应报文(response) => {// console.log(response?.data);// console.log(response?.data?.errMsg);// console.log(response?.data?.code === 200)// if(response?.data?.code !== 200){//    return Promise.reject(response?.data?.errMsg ? response?.data?.errMsg : "接口异常");// } return response.data;},// 请求错误时,或者axios代码报错时(error) => {return Promise.reject(error);}
);export default instance;

http.js文件:

import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import instance from "./config";
const get = (url)=>{// axios的实例instance会有一个get方法进行二次封装return instance.get(url);
}
const post = (url, data, config)=>{// axios的实例instance会有一个post方法进行二次封装// config配置文件,可不传,默认会使用axios内部的配置,可以使用第三个参数覆盖config.js里面的instance配置// https://www.axios-http.cn/docs/req_config-->请求配置return instance.post(url, data, config);
}export {get,post
}

AJAX实现原理

AJAX就是浏览器提供API,通过JS调用,从而实现通过代码实现请求和响应。

实现原理:

  1. 创建一个XMLHttpRequest
var xhr = new XMLHttpRequest()
  1. open三个参数,分别是get/post , url地址 ,是否异步(true/false)
xhr.open("GET","http://-----",false)
  1. 监听 onreadystatechange,判断readystate属性(五个值,0,1,2,3,4),判断当值为4的时候为成功 readystate == 4 && state == 200
xhr.onreadystatechange = function(){if(xhr.readystate != 4){return}if(xhr.readystate == 4 && xhr.state == 200){console.log(xhr.responseText)}
}
  1. 敲回车,send发送请求
xhr.send()

Ajax的优势:
①减轻了客户端的内存消耗,Ajax的理念是"按需取数据"。
②无刷新更新页面,提高用户体验。
③将一部分的工作量嫁到客户端,减轻服务器压力

ajax嵌套问题

一个请求需要另一个请求返回的结果作为参数时,就是ajax嵌套,会引起回调地狱的问题,上一个ajax报错,下面的都无法执行。解决方法:使用promise来解决回调地狱的问题。

Axios

  1. Axios是一个基于Promise的HTTP库,可以用在浏览器和node.js 中。

  2. Axios有那些特性?
    ①在浏览器中创建 XMLHttpRequests
    ②在node.js则创建http请求
    ③支持Promise API
    ④支持拦截请求和响应
    ⑤转换请求和响应数据
    ⑥取消请求
    ⑦自动转换成JSON数据格式
    ⑧客户端支持防御XSRF

  3. get和post请求
    get请求传参就是拼到url地址后面的,
    而post是放在 request body(请求体)中的。

  4. 常见的请求方式(接口的调用有几种方式?):get请求,post请求,put请求,delete请求

Axios和Ajax的区别

axios是通过Promise实现对ajax技术的一种封装,简单来说就是ajax技术实现了局部数据的刷新,axios实现了对ajax的封装,axios有的ajax都有,ajax有的axios不一定有。

promise

promise是为了解决回调地狱的问题,因为promise里面是异步的,后台请求数据是同步的,互不影响。

首先创建一个promise对象,接收一个函数作为参数,函数里面有两个参数,分别是resolve,reject。

promise内部有三种状态,pengding是初始状态,resolved是成功时候的状态,rejected是失败时候的状态。

promise的方法有.then方法,成功时候调用的方法,返回的依然是一个promise对象。.catch方法失败的时候调用的方法。.all方法,只有所有参数状态都成功时才会调用。.race方法只要一个状态成功,promise.race就会变成roselve。

new Promise((resolve,reject)=>{setTmieout(()=>{console.log("执行完成")resolve("数据")}2000)}).then((data)=>{console.log("resolve",data)}).catch((reson)=>{console.log("reject",reson)})

本地存储

当你想要存储用户相关的数据,本地存储是有用的,这样你就不必反复从数据库中查询数据。

可以使用 localStorage 的 setItem 方法来存储值在本地存储中

const ls = window.localStorage.setItem("name", "John Doe");

可以使用 getItem 方法来读取/检索你之前设置的值

const value = localStorage.getItem("name");
console.log(value);

可以使用 removeItem 方法从本地存储中删除键值对条目。

localStorage.removeItem("name");
console.log("name") // undefined

可以使用 clear 方法从本地存储中删除所有条目

localStorage.clear();

举例:

<template><div class="Add"><inputtype="text"placeholder="用户名"v-model="name"@input="saveState"/><button type="button" class="btn" @click="add">提交</button></div>
</template><script>
export default {name: "Add",data() {return {name: "",};},created() {this.loadState();},methods: {// 每当输入框发生变化时,saveState 方法被触发// 设置本地存储 localStorage.setItem,一般以JSON字符串的形式存储saveState() {localStorage.setItem('myVueState', JSON.stringify({ name: this.name }));},loadState() {// 读取本地存储数据const state = JSON.parse(localStorage.getItem('myVueState'));if (state) {this.name = state.name || '';}}},
};
</script>
<style scoped>
</style>

ECharts的安装与使用

ECharts官网:

https://echarts.apache.org/

1. npm安装ECharts

https://echarts.apache.org/handbook/zh/basics/import

npm install echarts --save

2. 按需引入ECharts

找到需要用到的示例,点击完整代码,把按需引入和
ES Modules按钮都打开,查看下面代码,然后放到我们自己的页面组件中即可。

要给图标所在的div加上宽度和高度才能显示,根据需求修改里面的数据和配置

<template><div class="strip"><h3>数据分析</h3><div class="Cartogram" id="Cartogram"></div></div>
</template>
<script setup>
import * as echarts from "echarts/core";
import {TitleComponent,TooltipComponent,GridComponent,LegendComponent,
} from "echarts/components";
import { BarChart } from "echarts/charts";
import { CanvasRenderer } from "echarts/renderers";
import { onMounted, reactive} from "vue";
echarts.use([TitleComponent,TooltipComponent,GridComponent,LegendComponent,BarChart,CanvasRenderer,
]);
let mapList = reactive({year: 2023,years: 2024,list: [{orgName: "苹果",num1: 18203,num2: 19325,},{orgName: "香蕉",num1: 23489,num2: 23438,},{orgName: "橘子",num1: 29034,num2: 31000,},{orgName: "芒果",num1: 104970,num2: 121594,},{orgName: "榴莲",num1: 131744,num2: 134141,},],
});
const onCart = () => {let chartDom = document.getElementById("Cartogram");let myChart = echarts.init(chartDom);let option = {// title: {//   text: "World Population",// },tooltip: {trigger: "axis",axisPointer: {type: "shadow",},},legend: {},grid: {left: "3%",right: "4%",bottom: "3%",containLabel: true,},xAxis: {type: "value",boundaryGap: [0, 0.01],},yAxis: {type: "category",// data: ["Brazil", "Indonesia", "USA", "India", "China", "World"],data: mapList.list?.map((item) => item.orgName),},series: [{// name: "2011",name: mapList.year,type: "bar",// data: [18203, 23489, 29034, 104970, 131744, 630230],data: mapList.list?.map((item) => item.num1),},{// name: "2012",name: mapList.years,type: "bar",// data: [19325, 23438, 31000, 121594, 134141, 681807],data: mapList.list?.map((item) => item.num2),},],};option && myChart.setOption(option);
};
onMounted(() => {onCart();
});
</script>
<style scoped lang="less">
.strip {width: 100%;height: 50%;.Cartogram {width: 100%;height: 100%;}
}
</style>

vue.config.js:

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,//是否开启eslint保存检测 ,它的有效值为 true || false || 'error'lintOnSave: false,// 服务器请求相关的配置devServer: {open: true, //启动项目后自动开启浏览器// host: 'locahost', //对应的主机名port: 8090, //端口号https: false, //是否开启协议名,如果开启会发出警告// hotOnly: false, //热模块更新的一种东西,webpack中自动有过配置,但如果我们下载一些新的模块可以更好的给我更新一些配置proxy: {//配置跨域"/er": {//配置跨域的名字target: "http://1.117.236.127", //跨域的地址logLevel: "debug",ws: true,changOrigin: true //是否跨域},"/ews": {//配置跨域的名字target: "http://42.192.185.85/", //跨域的地址logLevel: "debug",ws: true,changOrigin: true, //是否跨域pathRewrite: {"^/ews": "/er"}},// "/hsk": {//   //配置跨域的名字//   target: "http://1.117.236.127", //跨域的地址//   logLevel: "debug",//   ws: true,//   changOrigin: true, //是否跨域//   pathRewrite: {//     "^/hsk": ""//   }// },"/lyz": {//配置跨域的名字target: "http://192.168.110.90:9097", //跨域的地址logLevel: "debug",ws: true,changOrigin: true, //是否跨域pathRewrite: {"^/lyz": ""}}}}
})

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com