Vue2电商项目(二) Home模块的开发;(还需要补充js节流和防抖的回顾链接)

本文主要是介绍Vue2电商项目(二) Home模块的开发;(还需要补充js节流和防抖的回顾链接),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、Home模块拆分
    • 1. 三级联动组件TypeNav
    • 2. 其余组件
  • 二、发送请求的准备工作
    • 1. axios的二次封装
    • 2. 统一管理接口API----跨域
    • 3. nprogress进度条
  • 三、 vuex模块开发
  • 四、TypeNav三级联动组件开发
    • 1. 动态展示三级联动数据
    • 2. 三级联动 动态背景
      • (1)、方式一:CSS样式
      • (2)、方式二:JS
    • 3. 控制二三级数据隐藏与显示--绑定style样式
    • 4. 三级联动的节流和防抖
    • 5. 三级联动路由跳转及传参
      • (1)、编程式导航+事件委托--自定义属性
    • 6、 Search模块三级联动显示与隐藏
      • (1)、Search模块使用TypeNav组件
      • (2)、控制TypeNav的显示与隐藏
      • (3)、鼠标移入移出与TypeNav的显示与隐藏
      • (4)、三级联动显示与隐藏的动画效果
    • 7、 TypeNav重复发送请求的优化
    • 8. 合并Search页面的query与params参数
  • 六、Home首页的ListContainer和Floor组件
    • 1. 搭建mock
    • 2. 搭建ListContainer组件
      • (1)、 mock虚拟数据的ajax请求
      • (2)、 获取轮播图数据
      • (3)、 搭建轮播图
        • - 创建Swiper实例的讨论
    • 3. 搭建Floor组件
      • (1)、封装api、发送请求
      • (2)、 动态数据渲染页面
      • (3)、 Floor组件里的轮播图
      • (4)、 封装轮播图

一、Home模块拆分

通过对Home模块页面的分析,Home模块可包括7个组件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1. 三级联动组件TypeNav

由于这个组件在Home页面、Search页面、Detail页面中都使用了,所以把该组件注册为全局组件。
好处:只需要注册一次,就可以在任何地方使用

全局注册:Vue.component('组件名',组件)
在这里插入图片描述

2. 其余组件

拆分的时候注意样式CSS、结构HTML及图片资源
在这里插入图片描述
记录一个Bug,在ListContainer组件里,右侧的广告图片不显示(宋仲基那个图)
原因是浏览器安装的屏蔽广告插件把这个广告屏蔽了,所以报错。
参考博客:GET http://localhost:8080/***.png net::ERR_BLOCKED_BY_CLIENT 无法加载图片_localhost图片加载不出来-CSDN博客

二、发送请求的准备工作

1. axios的二次封装


(1)、为什么要对axios进行二次封装
  对axios二次封装可配置响应拦截器、请求拦截器:分别在收到服务器数据时或进行发送请求操作之前进行一些业务逻辑处理。

(2)、二次封装

  • 安装axios:npm install axios
    在这里插入图片描述

  • 创建src/api/request.js文件夹,进行二次封装

    // 本文件用于对axios二次封装
    import axios from 'axios'// 1. 利用axios方法create创建一个axios实例
    let requests = axios.create({// 配置实例属性// 1.1 基础路径,因为请求路径里都有api,所以这里设置基础路径baseURL: '/api',// 1.2 设置请求超时的时间。请求时间超过5s,则请求失败timeout: 5000
    });// 2. 配置请求拦截器
    // 请求拦截器检测到请求,在请求发出去之前做一些事情
    requests.interceptors.request.use((config) => {// config:配置对象,其中header请求头属性很重要return config;
    })// 3. 配置响应拦截器
    requests.interceptors.response.use((res) => {// 请求成功的回调函数return res.data
    }, (error) => {// 响应失败的回调return Promise.reject(new Error('falie'))
    })// 暴露axios实例
    export default requests
    

    对于axios,可参考NPM中关于axios的文档

2. 统一管理接口API----跨域

创建文件src/api/index.js,封装好发送请求的方法,发送请求时直接调用方法即可。

// src/api/index.js
// 本文件对于API接口进行统一管理
import requests from './request'// 三级联动
// 请求地址:/api/product/getBaseCategoryList,请求方法:get
export const reqCategoryList = () => {
// 发请求:axios发送请求返回结果Promise对象;
//axios二次封装里以及写了basedUrl,所以这里就不用写/api了
return requests({ url: '/product/getBaseCategoryList', method: 'get' })

测试方法:

// main.js
import { reqCategoryList } from './api'
reqCategoryList()

(1)、测试遇到的跨域问题:
跨域是指请求的 协议、域名、端口号不同
前端项目本地服务器:http://localhost:8080/#/home
后台服务器:http://gmall-h5-api.atguigu.cn

解决跨域 (具体细节回顾博客:配置代理服务器):

// vue.config.jsdevServer: {proxy: {'/api': {target: 'http://gmall-h5-api.atguigu.cn',}}}

请求成功:
在这里插入图片描述

3. nprogress进度条

nprogress:页面加载进度条。只要项目当中发请求,进度条就开始往前动,服务器数据返回之后,进度条结束。

  • 安装进度条插件:npm install nprogress
  • statrt():进度条开始
  • done():进度条结束
  • 在请求及响应拦截器中使用(进度条的颜色等样式可以修改,直接在css文件里修改即可)
    在这里插入图片描述

三、 vuex模块开发

Vuex具体细节看这篇博客:Vuex

这个项目中的vuex采用模块化开发,分别建立homesearch两个小仓库,然后放入store这个大仓库里。

// 小仓库
// store/home/index.js     store/search/index.js
export default {// 开启命名空间namespaced: true,state: {},actions: {},mutations: {},getters: {}
}

store大仓库:

在这里插入图片描述
main.js引入Vuex

// 引入Vuex
import store from '@/store'
new Vue({// KV一致时省略Vrouter,store,render: h => h(App),
}).$mount('#app')

四、TypeNav三级联动组件开发

1. 动态展示三级联动数据

向后台发送请求,获取三级联动的数据,渲染到页面上
在这里插入图片描述
TypeNav组件挂载完毕,就发送请求

mounted () {// 通知vuex发送请求,获取数据,存储在store中;dispatch('模块名/方法名')this.$store.dispatch('home/categoryList')
},

home小仓库里,将请求来的数据保存在state里:

//home/index.jsstate: {categoryList: []},actions: {// 获取三级联动的列表async categoryList (context) {let result = await reqCategoryList()if (result.code === 200) {// 请求成功context.commit('CATEGORTLIST', result.data)}}},mutations: {CATEGORTLIST (state, categoryList) {// 将获取成功的数据保存起来state.categoryList = categoryList}},

TypeNav组件读取vuex中请求来的数据

import { mapState } from 'vuex' 
computed: {// 获取State数据...mapState('home', ['categoryList'])},

通过循环遍历的方式将categoryList渲染到页面上
在这里插入图片描述
这里发现一个小bug;一级分类的数据多了一个,视频里请求到16个,结果获取到17个了,多了一个样式就变了;
解决:只用categoryList里的前16个,一级v-for的代码改成:

v-for="(c1, index) in categoryList.slice(0, 16)"

2. 三级联动 动态背景

在这里插入图片描述
需求1:鼠标移动到哪个词条,哪个词条背景颜色改变。离开时,背景颜色消失。
需求2:但是当鼠标由第一个词条图书、音像..移动到全部商品分类时,第一个词条的颜色不变。

(1)、方式一:CSS样式

.item:hover{background-color:skyblue
}

这种方式能够实现需求1,但实现不了需求2

(2)、方式二:JS

设置mouseentermouseleave事件及currentIndex属性,该属性默认值是-1;

当鼠标移入词条时,获取当前词条的index,存入currentIndex。当index === currentIndex时,给当前词条添加样式。

当鼠标移除词条时,再次将currentIndex设为-1;

<divclass="item"v-for="(c1, index) in categoryList.slice(0, 16)":key="c1.categoryId"@mouseenter="changeBg(index)":class="{ cur: index === currentIndex }"><!----一级分类a标签----><!----二级分类内容----><!----三级分类内容----></div>
<script>data () {return {currentIndex: -1}},methods: {changeBg (index) {this.currentIndex = index},leaveIndex () {this.currentIndex = -1}}
</script>>
<style>.cur {background-color: skyblue;}
</style>

为实现需求2,将全部商品分类与下方三级联动数据包裹在一个div里,将鼠标移出事件添加在这个div里

 <div @mouseleave="leaveIndex"><h2 class="all">全部商品分类</h2><div>..三级联动数据...</div>
</div>

3. 控制二三级数据隐藏与显示–绑定style样式

在这里插入图片描述

4. 三级联动的节流和防抖

1、什么是节流和防抖
  事件触发的非常频繁时,每一次的触发,回调函数都要去执行。但是如果触发的十分频繁而回调函数内部有计算等其他内容,则很可能出现浏览器卡顿,导致只有几次触发得到响应。

节流:在规定的间隔时间范围内不会重复触发回调,把频繁触发变为少量触发。

防抖:前面的所有的触发都被取消,也就是如果有连续快速的触发,只会执行一次。

应用:某些轮播图,快速点击切换图片时,可进行防抖或节流。

防抖:用户操作频繁,无关规定时间长短,期间只执行一次。
节流:用户操作很频繁,但是把频繁的操作变成少量操作【可以给浏览器充裕的时间解析代码】即规定时间执行一次。

具体看JS博客

2、三级联动节流
当鼠标快速从上往下移动时(即用户操作频繁),并不是所有词条的mouseenter事件都被触发。
在这里插入图片描述
节流采用lodash库提供的函数,由于vue中包含了lodash,所以不用提前安装

// 全部功能函数引入import _ from 'lodash'
// 或采用 按需引入
import throttle from 'lodash/throttle' methods:{/*正常情况(用户慢慢操作):鼠标进入每一个一级分类的h3,都会触发鼠标进入事件非正常情况(用户操作很快):只有部分触发进入事件,这是由于用户行为过快,导致浏览器反应不过来。如果当前回调函数中有一些大量业务,则有可能出现卡顿*/// 这里的throttle回调函数别用箭头函数,可能出现上下文this问题changeBg: throttle(function (index) {this.currentIndex = indexconsole.log('鼠标进入词条' + index);}, 50) 
}

5. 三级联动路由跳转及传参

需求:用户点击三级联动中的一级分类、二级分类、三级分类时,Home模块跳转到Search模块,并且在路由跳转时,将categoryNamecategoryId携带过去

在这里插入图片描述

1、路由跳转的方式

(1)、声明式导航router-link

router-link本质上是一个组件,当服务器的数据返回之后,会循环创建、渲染出很多的router-link实例组件。由于三级联动中链接较多,一瞬间创建很多组件实例十分消耗内存。因此采用router-link会出现卡顿现象。

(2)、编程式导航

 可通过添加监听点击事件实现路由跳转。但是每个a标签都要绑定自己的回调,这样不太好。
 只绑定一个回调要比绑很多回调要好,所以考虑采用事件委托的方式。事件委托是将点击事件添加到父节点中,这样任意子节点的事件都会冒泡到父节点,进而父节点的触发点击事件、调用回调函数。回顾事件委托:WebAPI(二)、事件委托

综上,采用编程式导航+事件委托的方式实现路由跳转。而这种方式存在两个问题。

(1)、编程式导航+事件委托–自定义属性

问题:

1.事件委托是把全部的子节点【h3、dt、dl】的事件都委派给父节点,如何确定点击的一定是a标签呢

2.即使确定点击的是a标签,如何区分是一级、二级、三级分类的标签。

解决方法:采用自定义属性
回顾自定义属性:WebAPI(一)、自定义属性

给a标签加上自定义属性,通过event.target.dataset获取到这些自定义属性

在这里插入图片描述
选择div父节点,绑定点击事件
在这里插入图片描述

// 跳转search页面
goSearch (event) {// 解构赋值,只有a标签才有这些自定义属性const { categoryname, category1id, category2id, category3id } = event.target.dataset// 组装参数let location = { name: 'search' }let query = { categoryName: categoryname }// 当前这个if语句:一定是a标签才会进入if (categoryname) {if (category1id) {  // 一定是a标签:一级分类query.category1Id = category1id} else if (category2id) {   // 一定是a标签:二级分类query.category2Id = category2id} else {  // 一定是a标签:三级分类query.category3Id = category3id}}// 给location对象配置上query属性location.query = querythis.$router.push(location)
}

6、 Search模块三级联动显示与隐藏

Search页面也有一个三级联动,且刚进入这个界面时,三级联动数据并不展示。鼠标移入全部商品分类时展示数据,离开时隐藏数据。

(1)、Search模块使用TypeNav组件

由于TypeNav组件是一个全局组件,直接使用即可

在这里插入图片描述

(2)、控制TypeNav的显示与隐藏

可以在TypeNav中使用v-show来决定TypeNav是显示还是隐藏。新增一个属性isShow
在这里插入图片描述
当由Home页面进入Search页面时,TypeNav组件会再重新挂载,所以在TypeNav挂载时(即钩子函数mounted),通过当前的路由信息,就决定这个组件是该显示还是隐藏。TypeNav是非路由组件,其$route信息是当前路由组件的信息。如果当前路由不是Home模块,即路径不是/home时,则隐藏。
在这里插入图片描述

(3)、鼠标移入移出与TypeNav的显示与隐藏

  当鼠标移入全部商品分类这一大块内容时,无论是home页面还是search页面,TypeNav都是显示的,所以isShow=true
   当鼠标移出这部分时,home页面中,这部分不隐藏。其他页面中,还是要隐藏起来。所以鼠标事件的回调函数如下图所示:

在这里插入图片描述

(4)、三级联动显示与隐藏的动画效果

transition标签:
在这里插入图片描述

// 过渡
// 进入的起点,离开的终点
.sort-enter,
.sort-leave-to {opacity: 0;
}
// 进入及离开的过程
.sort-enter-active,
.sort-leave-active {transition: all 0.3s linear;
}
// 进入的终点,离开的起点
.sort-enter-to,
.sort-leave {opacity: 1;
}

7、 TypeNav重复发送请求的优化

由于多个页面都使用了TypeNav组件,当进入Home页面时,TypeNav加载一次。进入Search页面时又加载一次。而三级联动数据的请求写在了TypeNav组件的mounted函数里,所以切换页面时会重复发送请求,而数据都是一样的,发一次请求就够了,没必要多次发送。

解决方法:请求写在根组件(App.vue)里

在这里插入图片描述
根组件只加载一次,所以只发送一次请求。

8. 合并Search页面的query与params参数

目前跳往Search页面的情况有两种:

  • Header组件中,输入关键词,点击搜索。跳转到Search页面(携带params参数)
  • TypeNav组件中,点击分类,跳转到Search页面(携带query参数)。
    在这里插入图片描述
    但是当先通过点击三级联动的链接跳转到搜索页面(有query参数),再通过关键词搜索(携带params参数)跳转Search页面时,三级联动的参数则会不见。

比如通过三级联动点击"手机",跳转到搜索页面,路径显示为:

localhosr:8080/#/search?categoryName=手机&category3Id=61

然后再通过搜索框搜索"华为":

localhosr:8080/#/search/华为

解决方法:将Header.vue里的回调函数加上query参数

// Header.vue
goSearch () {this.$router.push({name: 'search',params: {keyWord: this.keyWord || undefined},query: this.$route.query})
}

在这里插入图片描述

这里本来还有一个if判断,判断query是否为空,但是不起作用,具体原因博主DantinZhang有写过; 参考博客:Vue2电商前台项目(二):完成Home首页模块业务_电商开源项目vue-CSDN博客

六、Home首页的ListContainer和Floor组件

1. 搭建mock

(1)安装mock:npm install mockjs,并在src文件夹下新建mock文件夹,方便进行mock的配置

(2)创建数据文件:

  • 轮播图banner数据文件src/mock/banner.json
  • 楼层数据文件:src/mock/floor.json

(3)把数据文件里用到的图片资源放到src/images文件夹里。

(4) 在mock文件夹下创建mockServe.js,进行配置
在这里插入图片描述
(5) 在main.js文件里引入 mockServe.js,让假数据一上来就先执行一下

import './mock/mockServer'

2. 搭建ListContainer组件

(1)、 mock虚拟数据的ajax请求

  • 创建api/mockRequest.js
    之前二次封装的axios的用来给后台服务器发送请求的。对于向mock虚拟数据发送请求,同样先对axios进行二次封装。不同的是baseURL的值改为在mockServe.js里设置的请求路径
    在这里插入图片描述
  • 放入api/index.js中,统一进行api管理
import mockRequests from './mockRequest'
// 获取轮播图数据的api
export const reqBannerList = () => {return mockRequests({ url: '/banner', method: 'get' })

(2)、 获取轮播图数据

Listcontainer组件发送请求,获取数据,存到Vuex里,组件获取Vuex的数据

(3)、 搭建轮播图

  • 安装Swiper:npm install swiper@5

    • Swiper基本使用:Swiper中文网-轮播图幻灯片js插件,H5页面前端开发
  • 引包: import Swiper from 'swiper'

  • 引样式:import 'swiper/css/swiper.css'; 由于页面中不只这一处使用轮播图,所以样式可以从主文件(main.js)中引入。

    此时轮播图只是静态样式,原因是还未创建实例

- 创建Swiper实例的讨论

创建实例之后,轮播图才有动态效果。问题是应该在什么时候,在哪里创建Swiper实例?

1、放在mounted函数?

mounted () {console.log('listContainer--Mounted加载');// 发送请求并将数据存储在vuex里console.log('发送ajax请求');this.$store.dispatch('home/getBannerList')// 创建实例console.log('new Swiper实例');new Swiper('.swiper-container',{...})
}

轮播图仍未静态的。new Swiper实例之前,页面中的结构应该要完整。mounted里有一个异步操作,会导致创建实例先执行,当new Swiper实例时,该组件还未获取到数据,v-for渲染结构并不完全,也就是此时的结构是不完整的。所以此时仍是静态效果

3、采用setTimeout异步函数
在mounted函数里,存在的问题是先创建了实例,后有的数据,所以才不起作用。那考虑如何现有数据,再创建实例------采用异步函数

mounted () {console.log('listContainer--Mounted加载');// 发送请求并将数据存储在vuex里this.$store.dispatch('home/getBannerList')// 设置定时器,等组件获取到请求的数据之后,再实例化SwpiersetTimeout(() => {console.log('new Swiper实例');new Swiper('.swiper-container', {...}, 1000)
}

这种方式可以,但不是最优,因为发送ajax请求的时间不确定,所以定时器时间不好把握

4、watch+$nextTick(最优)

  • 数据监听watch:监听已有数据变化
  • $nextTick: 在DOM更新结束后,立即调用这个$nextTick的回调函数。也就是执行这个回调的时候,能够保证服务器的数据回来了,v-for执行完毕了(即轮播图的结构已经完成了)。$nextTick可以保证页面中的结构一定是有的,经常和很多插件一起使用。要是还不明白,回顾博客 Vue(九) nextTick。
watch: {// 监听bannerList数据的变化,因为这条数据发生过变化---由空数组变为数组里有4个元素bannerList: {handler () {this.$nextTick(() => {new Swiper('.swiper-container', {loop: true, // 循环模式// 如果需要分页器pagination: {el: '.swiper-pagination'},// 如果需要前进后退按钮navigation: {nextEl: '.swiper-button-next',prevEl: '.swiper-button-prev',}})})}}}

watch监听bannerList属性的属性值的变化,当handler函数执行时,只能保证bannerList的数据已经有了,不再是空数组,但是没办法保证v-for已经将这些数据渲染完成。当v-for渲染完成后,结构才完整。因此采用nextTick

3. 搭建Floor组件

经典流程:封装api => 组件挂载完毕时发送请求、获取数据 => 数据存到Vuex中(vuex三件套state、actions、mutations) =>渲染页面

(1)、封装api、发送请求

api/index.js里封装api

// Floor数据
export const reqFloorList = () => {return mockRequests({ url: '/floor', method: 'get' })
}

Vuex保存数据及Home组件获取数据
(回顾Home页面,Home页面中有两个<Floor/>标签,需要通过v-for来遍历生成floor组件,所以需要在Home组件中进行dispatch。)
在这里插入图片描述

(2)、 动态数据渲染页面

Home组件将数据传递给子组件Floor

(高频面试题,父组件给子组件传值的方式/组件通信的方式有哪些?
props、自定义事件:Vue(八) props 自定义事件
全局事件总线、消息订阅与发布:Vue(九)全局事件总线、消息订阅与发布
插槽:Vue(十一) 插槽
Vuex: Vue(十二) Vuex

<!-- Home.vue -->
<Floor v-for="f in floorList" :key="f.id" :list="f"></Floor>
<!-- Floor.vue -->
props: ['list']

(3)、 Floor组件里的轮播图

在Floor里,new Swiper实例可以放在mounted里,因为Floor里的数据是父组件Home传递过来的,Floor里没有任何异步操作,所以挂在完毕之后页面结构就会现有,所以创建Swiper实例是可行的。(之前ListContainer组件内发送了异步请求,当创建Swiper实例时,由于数据不全,所以轮播图的结构并不完整)

(4)、 封装轮播图

  由于轮播图在多个组件中用到,所以可将轮播图封装为全局组件。前提是保证目前用到轮播图的地方,轮播图的代码一致。根据上边可知,ListContainer组件和Floor组件的区别是new Swiper实例的地方不一致,ListContainer用的是watch+$nextTick, Floor用的是mounted。

让Floor组件向ListContainer组件看齐,将new Swiper实例放到watch监听里:

list: {// 因为Floor中的list数据是父组件传过来的,没有发生过变化,所以需要上来立即执行一次监听,创建Swiper实例。immediate: true,handler () {// 数据已经有了,但是v-for动态渲染结构还是没有办法确定,因此还是需要nextTickthis.$nextTick(() => {new Swiper(this.$refs.mySwiper, {loop: true, // 循环模式pagination: { // 如果需要分页器el: '.swiper-pagination',clickable: true},navigation: { // 如果需要前进后退按钮nextEl: '.swiper-button-next',prevEl: '.swiper-button-prev',}})})}
}

最终封装为Carousel组件:

<!--src/components/Carousel/index.vue--> 
<template><div class="swiper-container" ref="mySwiper"><div class="swiper-wrapper"><div class="swiper-slide" v-for="(s, index) in list" :key="index"><img :src="s.imgUrl" /></div></div><!-- 如果需要分页器 --><div class="swiper-pagination"></div><!-- 如果需要导航按钮 --><div class="swiper-button-prev"></div><div class="swiper-button-next"></div></div>
</template>
<script>
import Swiper from 'swiper'
export default {name: 'Carousel',props: ['list'],// 监听List数据的变化,//ListContainer组件中的这条数据发生过变化(由空数组变为数组里有4个元素),所以可用watch监听watch: {list: {// 因为Floor中的list数据是父组件传过来的,没有发生过变化,所以需要上来立即执行一次监听,创建Swiper实例。immediate: true,handler () {// 数据已经有了,但是v-for动态渲染结构还是没有办法确定,因此需要nextTickthis.$nextTick(() => {new Swiper(this.$refs.mySwiper, {loop: true,pagination: { // 如果需要分页器el: '.swiper-pagination',clickable: true},navigation: { // 如果需要前进后退按钮nextEl: '.swiper-button-next',prevEl: '.swiper-button-prev',}})})}}}
}
</script>

这篇关于Vue2电商项目(二) Home模块的开发;(还需要补充js节流和防抖的回顾链接)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147926

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于