实习总结 - web前端 | MrNobody = MrNobody's Blog = 保持呼吸 不要断气

昨天给组长姐姐看我写的代码,她表示很不戳,但要让我来总结一下学到什么东西,那我就把实习这段时间学到东东的放在这里吧

# 节流防抖

# 防抖 (debounce)

单位时间内,频繁触发事件,只执行最后一次

使用场景

搜索框输入,手机号,邮箱验证输入检测

思路

核心是利用 setTimeout 定时器来实现

  1. 声明定时器变量
  2. 每次事件触发时要先判断是否有定时器,如果有,先清除以前的定时器
  3. 如果没有定时器,则开启定时器,存入到定时器变量中
  4. 定时器里面写函数调用
function debounce ( fn , time ){
  let timer
  //return 返回一个匿名函数 如果不返回就只会执行一次
  return function () {
    // 判断是否有定时器,如果有就清除定时器
      if (timer) clearTimeout(timer)
      // 没有则添加定时器
      timer = setTimeout(()=>{
        // 触发定时器里面的函数
        fn()
      },time)
  }
}

# 节流 (throttle)

单位时间内,频繁触发事件,只执行一次

使用场景
高频事件:鼠标移动 mousemove, 页面尺寸缩放 resize,滚动条滚动 scroll 等等

思路

节流的同样是利用定时器来实现

  1. 声明一个定时器变量
  2. 当事件触发都先判断是否有定时器了,如果有定时器,则不开启新的定时器
  3. 如果没有定时器则开启定时器,记得存到变量里面
  4. 定时器里面调用执行的函数,定时器里面要把定时器清空
function throttle(fn,time){
  let timer = null
  return function(){
    if (!timer) {
    timer = setTimeout(()=>{
        fn()
        //setTimeout 无法删除定时器,因为定时器还在运作,所以不用 clearTimeout
        timer= null
      },time)
    }
  }
}

# 使用 lodash 节流防抖

  1. 安装 lodash
    npm i --save lodash

  2. 按需导入 lodash
    import { debounce } from 'lodash'

  3. 用这种姿势来使用

<button @click="addCount">+1</button>
addCount: debounce(function () {
  this.count++
}, 1000)

ps: 箭头函数中没有自己的 this 值,所以用普通函数来实现

# 点击按钮实现网页全屏效果

在 Vue 中你可以通过使用 @click 事件和 Fullscreen API 来实现点击按钮全屏网页的功能。以下是一个示例:

<template>
  <div>
    <button @click="toggleFullScreen">全屏</button>
  </div>
</template>
<script>
export default {
  methods: {
    toggleFullScreen() {
      var elem = document.documentElement;
      if (!document.fullscreenElement && !document.mozFullScreenElement &&
        !document.webkitFullscreenElement && !document.msFullscreenElement) {
        if (elem.requestFullscreen) {
          elem.requestFullscreen();
        } else if (elem.mozRequestFullScreen) { // Firefox
          elem.mozRequestFullScreen();
        } else if (elem.webkitRequestFullscreen) { // Chrome, Safari and Opera
          elem.webkitRequestFullscreen();
        } else if (elem.msRequestFullscreen) { // IE/Edge
          elem.msRequestFullscreen();
        }
      } else {
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.mozCancelFullScreen) { // Firefox
          document.mozCancelFullScreen();
        } else if (document.webkitExitFullscreen) { // Chrome, Safari and Opera
          document.webkitExitFullscreen();
        } else if (document.msExitFullscreen) { // IE/Edge
          document.msExitFullscreen();
        }
      }
    }
  }
};
</script>

# 父组件调用子组件方法

  1. 在父组件内部给子组件标签添加 ref 属性
<son ref="son"></son>
  1. 通过 ref 属性来调用子组件的方法。
this.$refs.son.sonFn()

父组件

<template>
  <div id="app">
    <div class="fatherBox">
      <button @click="fatherBtn">父组件的按钮</button>
    </div>
    <mySon ref="son"></mySon>
  </div>
</template>
<script>
import mySon from '@/components/mySon.vue';
export default {
  name: 'app',
  components: {
    mySon
  },
  methods: {
    fatherBtn() {
      // 使用子组件的方法
      this.$refs.son.addCount()
    }
  },
}
</script>

子组件

<template>
  <div id="son">
    <div>我是子组件的值:<!--swig0--></div>
  </div>
</template>
<script>
export default {
  name:'mySon',
  data() {
    return {
      count: 0,
    }
  },
  methods: {
    addCount() {
      this.count++
    }
  }
}
</script>

# Mixins 混入

作用:复用代码,Mixins 可以定义所有组件里面可以定义的东西 例如 data,methods,created 等等

使用方式:

  1. 首先在 src 目录下新建 Mixins 文件
  2. 在 Mixins 文件中输入想要实现的功能并导出
export const showBox = {
  data() {
    return {
      isShow: true
    }
  },
  methods: {
    showBox() {
      this.isShow = !this.isShow
    }
  }
}
  1. 导入 Mixins 并且注册
import mySon from '@/components/mySon.vue';
export default {
  mixins: [showBox],
}
  1. 直接使用 Mixins 的方法即可
<button @click="showBox">显示或者隐藏盒子</button>
<div class="box" v-if="isShow"></div>
  1. 子组件复用代码 使用同样步骤

完整代码

mixins 代码

export const showBox = {
  data() {
    return {
      isShow: true
    }
  },
  methods: {
    showBox() {
      this.isShow = !this.isShow
    }
  }
}

父组件使用代码

template>
  <div id="app">
    <button @click="showBox">显示或者隐藏盒子 <!--swig1--></button>
    <div class="box" v-if="isShow"></div>
    <mySon></mySon>
  </div>
</template>
<script>
import { showBox } from '@/Mixins/showBox'
import mySon from '@/components/mySon.vue';
export default {
  components: { mySon },
  name: 'app',
  mixins: [showBox],
}
</script>

子组件使用代码

<template>
  <div id="son">
    <button @click="showBox">显示或隐藏子组件的盒子</button>
    <div class="box" v-if="isShow">我是子组件的盒子</div>
  </div>
</template>
<script>
import { showBox } from '@/Mixins/showBox'
export default {
  name: 'mySon',
  mixins: [showBox],
}
</script>

# computed 和 watch 的区别

  1. 计算属性可以像普通属性一样在模板中使用,侦听器不行
  2. 计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值
  3. 侦听器监测的是属性值,如果属性值发生变化,都会触发执行回调函数来执行一系列操作,侦听器也可以监测计算属性
  4. 计算属性无法执行异步任务,只能同步执行,也就是说计算属性不能向服务器请求或者执行异步任务,侦听器可以。
watch: {
    async username(newVal, oldVal) {
     await axios.get()
    },
  }

# 闭包的使用,了解其优缺点

概念: 一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域

闭包的作用: 封闭数据,提供操作,外部也可以访问函数内部的变量

简单理解: 闭包 = 内层函数 + 外层函数的变量

闭包的缺点: 常驻内存,会增大内存使用量,使用不当会造成内存泄漏

闭包的基本格式

function outer () {
let a = 10
  function fn () {
    console.log(a)
  }
  return fn()
}
// 外面要使用这个 10 
const fun =  outer()
fn() 
// 外层函数使用内层函数的变量

# vh vw px rem em upx rpx 的关系与区别

# vw 和 vh

vw 和 vh 是 CSS 中用于定义相对长度的单位
vw 代表视口宽度的百分比单位,1vw 等于视口宽度的 1%,例如视口宽度为 1000px,1vw 等于 10px

# em 和 rem

em 和 rem 是 CSS 中用于定义相对长度的单位,它们对于元素的字体大小进行计算。

  • em:相对于父元素的字体大小进行计算,如果一个元素的字体大小为 16px,设置它的宽度为 2em,那么它的宽度将是 32px (2 * 16)

  • rem:相对于根元素(通常指 html 元素)的字体大小进行计算,如果根元素的字体大小为 16px,设置一个元素的宽度为 2rem,那么它的宽度也将是 32px (2 * 16)。rem 单位主要用于构建响应式布局。

相比 em,rem 具有更好的可控性,当使用 em 单位时,嵌套元素会继承父元素的字体大小,并可能导致计算机混乱。而 rem 的优点就是可以通过修改 html 里面的文字大小来改变页面中元素的大小,可以整体控制。

# upx 和 rpx

upx(设备像素)和 rpx(响应式像素)是微信小程序中常用的长度单位。

  • upx:设备像素,是物理像素的概念,即设备屏幕上的实际像素点。在微信小程序中,1 个 upx 等于 1 个物理像素的宽度。

  • rpx:响应式像素,是一种相对长度单位,是微信小程序为了适配不同设备屏幕而提出的概念。在微信小程序中,1 个 rpx 可以根据屏幕宽度进行自适应转换,假设屏幕宽度为 750rpx,那么屏幕宽度为 375px 时,1rpx 即为 1 物理像素。

# DOM 事件流

事件流描述的是从页面接收事件的顺序
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即为 DOM 事件流

DOM 事件流分位 3 个阶段:

  1. 捕获阶段
  2. 当前目标阶段
  3. 冒泡阶段

冒泡事件
它指的是当一个元素触发了某个事件,比如点击事件,这个事件将会从最内层的元素开始触发,然后逐级向父级元素传递,直到传递到最外层的元素。

捕获事件
在捕获事件模型中,事件从最外层的元素开始传递,逐级向内层元素传递,直到传递到最内层的元素。

注意

  • js 代码只能执行捕获或者冒泡其中一个阶段。
  • onclick 和 attachEvent 只能得到冒泡阶段
  • addEventListener 第三个参数如果是 true 表示在事件捕获阶段调用事件处理程序,如果是 false 或者不写 (默认 false), 表示在事件冒泡阶段调用事件处理程序
  • 实际开发中更关注事件冒泡

案例

捕获
冒泡
  • 捕获阶段:

    • document → html → body → father → son
    • 点击子盒子,先执行父盒子事件,后执行子盒子事件
  • 冒泡阶段:

    • son → father → body → html → document
    • 点击子盒子,先执行子盒子事件,再执行父盒子事件

阻止冒泡事件

可以在事件处理程序中使用 event.stopPropagation() 方法。该方法可以阻止事件进一步向上冒泡传递,使事件仅在当前元素上触发。

阻止
son.addEventListener('click', function (e) {
      alert('son')
      e.stopPropagation()
    })
father.addEventListener('click', function () {
  alert('father')
})

vue 中阻止冒泡事件

vue 可以通过使用修饰符 .stop 来阻止事件冒泡。

<template>
  <div class="test">
    <div class="father" @click="father">
      <div @click.stop="son" class="son"></div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'welcomeIndex',
  methods: {
    father () {
      alert('father')
    },
    son () {
      alert('son')
    }
  }
}
</script>

# 接口请求方式

使用 axios 代码进行演示

GET
用于从服务器获取数据。GET 请求将数据作为 URL 的一部分发送到服务器,并返回相应的响应数据。GET 请求通常用于获取资源,不应该用于发送敏感数据,因为数据会以明文形式出现在 URL 中。

axios.get('http://localhost:3000/user').then(res => {
  console.log(res)
})

POST
用于向服务器发送数据。POST 请求将数据作为请求的正文发送到服务器,通常用于提交表单数据或者发送较大的数据。POST 请求相对安全,因为数据不会以明文形式出现在 URL 中

axios.post('http://localhost:3000/user', {
  username: 'sadMan',
  name: '木子李',
  age: 20
}).then(res => {
  console.log(res)
})

PUT
用于向服务器更新资源。PUT 请求将数据作为请求的正文发送到服务器,用于更新特定 URL 指定的资源。PUT 请求通常用于更新整个资源

DELETE
用于从服务器删除资源。DELETE 请求用于删除特定 URL 指定的资源。

PATCH
用于对服务器资源进行部分更新。PATCH 请求用于更新特定 URL 指定的资源的一部分内容。

# 状态码

在 JavaScript 中,可以通过 HTTP 响应的状态码来获取请求的执行结果。HTTP 状态码是一个三位数的数字,用于表示服务器响应的状态和结果
200: 请求成功,服务器成功处理了请求,并返回所需的数据

201: 请求已创建,服务器成功处理了请求,并创建了新的资源

204: 请求成功,服务器成功处理了请求,但没有返回任何内容

400: 请求错误,服务器无法理解请求,通常是由于请求参数有误或语法错误导致

401: 未授权,需要进行身份验证或缺乏有效凭据

403: 访问被禁止,服务器理解请求,但拒绝执行,通常由于权限问题导致

404: 资源未找到,服务器未找到请求的资源

500: 服务器内部错误,服务器在请求时遇到了错误

503: 服务不可用。服务器当前无法处理请求,通常是由于临时过载或维护导致的。

# 请求头

HTTP 头字段(HTTP header fields), 是指在超文本传输协议(HTTP)的请求和响应消息中的消息头部分
它们定义了一个超文本传输协议事务中的操作参数
HTTP 头部字段可以自己根据需要定义,因此可能在 Web 服务器和浏览器上发现非标准的头字段

字段名说明示例
Authorization用于进行身份验证,传递访问令牌或凭据。常见的值为 Bearer token ,其中 toke 为访问令牌Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Accept能够接受的回应内容类型(Content-Types)Accept: text/plain
Accept-Charset能够接受的字符集Accept-Charset: utf-8
Cookie服务器通过 Set- Cookie (下文详述)发送的一个 超文本传输协议 CookieCookie: $Version=1; Skin=new;
Date发送该消息的日期和时间Date: Tue, 15 Nov 1994 08:12:31 GMT

# Git

# Git 仓库

Git 仓库是记录文件状态内容的地方,存储着修改的历史记录

  1. 可以把本地文件夹转化为 Git 仓库 git init
  2. 从其他地方克隆 git 仓库 git clone xxx.com

# Git 的三个区域

  1. 工作区:实际开发时操作的文件夹
  2. 缓存区:保存之前的准备区域 (暂存改动过的文件)
  3. 版本库:提交并保存暂存区中的内容,产生一个版本快照
命令作用
git add 文件名暂存指定文件
git add .暂存所有改动的文件
git ls-files查看当前项目下暂存区记录了那些文件
git commit -m "注释说明"提交并保存,产生版本快照

# Git 文件状态

git status -s 可以查看文件状态

文件状态概念场景
未跟踪 U从未被 Git 管理过新文件
新添加 A第一次被 Git 缓存之前版本记录没有此文件
已修改 M工作区内容变化修改了内容产生

# 回退版本

把版本库某个版本对应的内容快照,恢复到工作区和暂存区
查看提交历史: git log --oneline
查看完整提交日志 git reflog --oneline

  1. git reset --soft 版本号
  2. git reset --hard 版本号 强制覆盖工作区和暂存区的命令
  3. git reset --mixed 版本号

# 分支

创建分支命令: git branch 分支名
切换分支命令: git checkout 分支名
查看当前分支: git branch

合并其他分支: git merge 分支名
删除合并后的分支指针: git branch -d login-bug

# 远程仓库

  1. 新建仓库得到远程仓库 git 地址
  2. 本地 git 仓库添加远程仓库原点地址 命令: git remote add 远程仓库别名 远程仓库地址
  3. 本地 git 仓库推送版本记录到远程仓库 命令: git push -u 远程仓库别名 本地和远程分支名

# 上传图片并预览

这里有个上传文件的按钮

预览图片

<input type="file" id="fileInput" accept="image/*" onchange="previewImage(event)">
 <img id="preview" src="#" alt="预览图片" style="max-width: 300px; max-height: 300px;">
<script>
function previewImage(e) {
  // 获取选择的文件
  var file = e.target.files[0];
  
  if (file) {
    // 创建一个 FileReader 对象
    var reader = new FileReader()
    // 当文件读取完成时,触发 onload 事件
    reader.onload = function(e) {
      // 获取预览图片的元素
      var previewImage = document.getElementById('preview');
      // 将读取到的文件内容(base64 编码)赋值给预览图片的 src 属性
      previewImage.src = e.target.result;
    }
    // 读取文件内容,结果将在 onload 事件中处理
    reader.readAsDataURL(file);
  }
}
 </script>

# elementui 中的 upload

由于饿了么自带的上传图片非常好看,所以我大概看了一下文档,发现他和我想要的上传图片不太一样。

饿了么的上传,点击文件就会立马上传
不想让它立马上传的话,可以将组件属性 action 改为空 ,再将 auto-upload 设置成 false 就行

<el-upload  action=" " :auto-upload="false">
  <img v-if="imageUrl" :src="imageUrl" class="avatar">
  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>

下一步是预览图片,我们可以使用组件中的 on-change 钩子 官方文档说:文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用,它里面有两个参数 function(file, fileList)

所以我们可以通过 on-change 钩子来获得上传的图片文件

以下是完整代码

<!-- action 必选参数,上传的地址 -->
<!-- on-change 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用 -->
<!-- auto-upload 是否在选取文件后立即进行上传 -->
<!-- accept 接受上传的文件类型 -->
<!-- show-file-list 是否显示已上传文件列表 -->
<el-form-item label="文章封面" prop="cover_img">
  <el-upload class="avatar-uploader" action="" :on-change="getFile" :auto-upload="false" accept=".jpg, .png":show-file-list="false">
    <img v-if="imageUrl" :src="imageUrl" class="avatar">
    <i v-else class="el-icon-plus avatar-uploader-icon"></i>
  </el-upload>
</el-form-item>

同时在方法中判断文件类型,大小,也可以将文件转换成 base64 格式的字符串

// 文件状态改变时的钩子
getFile (file) {
  //  判断文件类型是否为图片
  const isJPG = file.raw.type === 'image/jpeg' || 'image/png'
  // 判断图片类型是否小于 2m
  const isLt2M = file.size / 1024 / 1024 < 2
  if (!isJPG) {
    return this.$message.error('上传头像图片只能是 JPG 或 PNG 格式!')
  }
  if (!isLt2M) {
    return this.$message.error('上传头像图片大小不能超过 2MB!')
  }
  // 设置图片预览
  this.imageUrl = URL.createObjectURL(file.raw)
  this.pubForm.cover_img = file.raw
  // 重新校验表单
  this.$refs.pubFormRef.validateField('cover_img')
  // 如果你想的话还可以将文件转换成 base64 格式的
  const fr = new FileReader()
  fr.readAsDataURL(file.raw)
  fr.onload = function (e) {
    // 这个就是 base64 的字符串啦
    console.log(e.target.result)
  }
}

# FormData

FormData 类是 HTML5 新出的专门为了装文件和其他的参数的一个容器

后端接口 form-data

pubForm: {
  // 表单的数据对象
  title: '',
  cate_id: '',
  content: '', // 文章内容
  cover_img: null, // 用户选择的封面图片(null 表示没有选择任何封面)
  state: '' // 文章的发布状态,可选值有两个:草稿、已发布
},
const fd = new FormData()
fd.append('title', this.pubForm.title)
fd.append('cate_id', this.pubForm.cate_id)
fd.append('content', this.pubForm.content)
fd.append('state', this.pubForm.state)
fd.append('cover_img', this.pubForm.cover_img)
// 在对 formData 使用 append 方法添加数据后,console 输出仍为空
// console.log(fd)  
// 需要用 formData.get ("键") 的方法获取值
// console.log(fd.get("title"))
const { data: res } = await addArticleApi(fd)
console.log(res)

简写

使用 Object.keys(this.pubForm) 获取 this.pubForm 对象的所有属性名,并使用 forEach 方法遍历这些属性名。

在遍历过程中,对于每个属性名 key,使用 fd.append(key, this.pubForm[key]) 将属性名和对应的属性值添加到 FormData 对象 fd 中。

Object.keys(this.pubForm).forEach((key) => {
  fd.append(key, this.pubForm[key])
})
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Mr_Nobody 微信支付

微信支付

Mr_Nobody 支付宝

支付宝

Mr_Nobody 贝宝

贝宝