关于某个小App创建并打包过程中的小细节

142 阅读5分钟

做完总结

//  这是下面的代码写的过程中需要的一些代码
import axios from 'axios';

import { S_IFIFO } from 'constants';

import { request } from 'http';

import { config } from 'process';

const ajax = axios.create({
  baseURl: 'dgdvc'
})

// data 忘记了

export default ({ url, method = 'get', headers, params, data }) => {
  return ajax({
    url,
    method,
    headers,
    params,
    data
  })
}

// Vant 定制主题需要记住的一样东西

const path = require('path');

${path.resolve(__dirname, '/src/styles/less.less')}

// Eslint

rules: {

  'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  
  'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  
  'space-before-function-paren': 'off',
   
   camelcase: 'off'
  
}

// 如何关闭 Eslint

d6b5758cd499a5cf28e71a40d090012.png

// 自己实现监视器

var observer = new IntersectionObserver(function (changes) {
  console.log(changes)
  changes.forEach(function (element, index) {
    // intersectionRatio 观察标签的固定属性, 大于0小于1证明在窗口范围内了
    if (element.intersectionRatio > 0 && element.intersectionRatio <= 1) {
      element.target.src = element.target.dataset.s // 就给标签设置src属性的值
    }
  })
})

// 在vue项目中创建全局自定义指令

Vue.directive('lala', {
  inserted (el, binding) { // 先给el添加个自定义属性s, 接收v-lala传入的图片真实地址
    el.dataset.s = binding.value
    observer.observe(el) // 绑定监视器
  }
})

// 多久之前

relativeTime (val) {
  const t = new Date(val)
  const diff = Date.now() - t.getTime()

  const year = Math.floor(diff / (1000 * 3600 * 24 * 365))
  if (year) {
    return `${year}年前`
  }
  const month = Math.floor(diff / (1000 * 3600 * 24 * 30))
  if (month) {
    return `${month}月前`
  }
  const day = Math.floor(diff / (1000 * 3600 * 24))
  if (day) {
    return `${day}天前`
  }
  const hour = Math.floor(diff / (1000 * 3600))
  if (hour) {
    return `${hour}小时前`
  }
  const minute = Math.floor(diff / (1000 * 60))
  if (minute) {
    return `${minute}分钟前`
  } else {
    return '刚才'
  }
}

// 添加请求拦截器 把token携带在请求头带给后台

 axios.interceptors.request.use(function (config) {

   在发送请求之前做些什么 (把token携带在请求头带给后台)
   if(store.state.token.length>0&&config.headers.Authorization===undefined ){
     config.headers.Authorization=`Bearer store.state.token`
   }

  return config;
 }, function (error) {
  // 对请求错误做些什么
   return Promise.reject(error);
 })
 

// 添加响应拦截器

 axios.interceptors.response.use(function (response) {
  //对响应数据做点什么
  return response;
 }, function (error) {


  // 对响应错误做点什么 (常见情况就是判断401时做什么)
  //发出refresh-token请求  得到新的token   赋值给vuex和本地token   并且重新把之前没完成的请求重新执行一次   error.config 就是上一次axios请求的配置对象
 if(error.response.statue===401){
 
   const res = await refreshTokenAPI()
   store.commit('setToken', res.data.data.token)
     
   error.config.headers.Authorization=`Bearer ${res.data.data.token}`
   retrurn  request(error.config)
}   
  return Promise.reject(error);
 })

// 浅拷贝 此处的情况是后台需要的数据和前端数据不一致 前端需要对数据进行更改才能得到后台需要的格式才能完成前端的数据更新

async updateFn () {
  // 处理数据
  // (重要): 先拷贝出来一份数组
  const newArr = this.channelList.map((obj) => {
    const newObj = { ...obj }
    return newObj
  })
  // (1):不能带推荐频道, 找到频道id为0的索引
  const index = newArr.findIndex((obj) => obj.id === 0)
  newArr.splice(index, 1)
  // (2):每个对象添加seq属性, 删除name属性
  newArr.forEach((obj, index) => {
    obj.seq = index + 1
    delete obj.name
  })
  // 传给后台
  const res = await updateChannelListAPI({
    channels: newArr
  })
  console.log(res)
}

// 封装自定义指令

import Vue from 'vue'
// 插件对象(必须有install方法, 才可以注入到Vue.use中)
export default {
  install () {
    Vue.directive('fofo', {
      inserted (el) {
        // 指令在van-search组件身上, 获取的是组件根标签div, 而input在标签内
        el = el.querySelector('input')
        el.focus()
      }
    })
  }
}

// 防抖 等用户动作结束一秒后再执行

export default {
  data () {
    return {
      kw: '', // 搜索关键字
      timer: null, // 防抖, 用的定时器
      suggestList: [] // 建议关键字列表
    }
  },
  methods: {
    async inputFn () {
      clearTimeout(this.timer)
      this.timer = setTimeout(async () => {
        if (this.kw.length === 0) return // 防止空内容触发下面逻辑
        const res = await suggestListAPI({
          q: this.kw
        })
        this.suggestList = res.data.data.options
      }, 500)
    }
  }
}

// 高亮

//   utiles/Ligth.js
export default LigthFn=(str,target)=>{
  const reg=new RegExp(target,'ig')

  return str.replace(reg,(match)=>{
    return `<span style='color:red'>{{match}}</span>`
  })
}

// 处理大数

const ajax = axios.create({
  baseURL: 'http://toutiao.itheima.net/', // 请求的基础路径
  transformResponse: [function (data) { // 对内容进行处理
    // data:就是本次请求获取的数据
    // 在这里可以对它进行进一步的处理 -- JSONbig
    // 后端返回数据可能不是 JSON 字符串,而JSONbig.parse()只能处理JSON字符串
    // 所以,为了保证代码可以正常执行,这里引入try-catch来捕获异常
    try {
      // 尝试着进行大数的处理
      return jsonBig.parse(data)
    } catch {
      // 大数处理失败时的后备方案
      return JSON.parse(data)
    }
  }]
})

// 封装自定义指令--获取焦点(input/textarea)

import Vue from 'vue'
// 插件对象(必须有install方法, 才可以注入到Vue.use中)
export default {
  install () {
    Vue.directive('fofo', {
      inserted (el) {
        if (el.nodeName === 'INPUT' || el.nodeName === 'TEXTAREA') {
          // 如果直接是input标签/textarea标签
          el.focus()
        } else {
          // 指令在van-search组件身上, 获取的是组件根标签div, 而input在标签内
          const inp = el.querySelector('input')
          const textArea = el.querySelector('textarea')
          // 如果找到了
          if (inp || textArea) {
            inp && inp.focus()
            textArea && textArea.focus()
          } else {
            // 本身也不是, 子标签里也没有
            console.error('请把v-fofo用在输入框标签上')
          }
        }
      }
    })
  }
}

// 关于token 与 refresh-token

9e2cd6f592c10bb37b308005250722e.png

// cookie LocalStorage sessionStorage

a2e780fb23beaaaefb859fa096e1e5a.png

// 封装axios 封装完之后发现没必要而且有弊处,所以大可不必

e3266704ab053d787bc3d8b3d264dfb.png

c92d166d09bdda83ea1fd47ab64644c.png

// 关于v-for 的 key

key必须是唯一不重复的字符串或数字,没有key的话 vscode会最大限度地尝试就地更改/复用相同类型元素 有key属性,就基于key来比较新旧虚拟DOM 而虚拟DOM是通过diff算法就地更新 移除key不存在元素 。 如果key的值为索引, 索引是从头往后排的,所以还是就地更新。 key为id的话,会去比较id,id是之前没有的就会服用相同类型的元素 新创建一个dom元素 结论:他只会新增新的数据的标签结构

2887064a1ef1ce22f3f3bb8e2c05f88.png

67cda9f81ac1932904f37f2d330264f.png

// 有一个是处理生日格式 对象->字符串 字符串->对象

bac7644cfe8e7ef1410f57339aeef6f.png

23ced9fff6ee9d241860a0b23cff7fe.png

 //对象->字符串   this.currentDate//这里的值是日期对象
moment(this.currentDate).format('YYYY-MM-DD')
 //字符串->对象
new Date(this.profile.birthday)

// 当接口文档里请求参数data的值为表单对象

bac7644cfe8e7ef1410f57339aeef6f.png

// 代码中普遍出现的一个问题是刷新后效果没实现 这时候很可能的原因就是太快了

48c32350358ae2c9f22426a538d88bc.png

// v-if 与 v-show 的不同

v-if的话就彻底销毁了 需要的时候重新再渲染 看情况而用一定

// 两个原生方法

el.scrollIntoView(true/false)
// true 的话表示元素的顶部与当前区域的可见部分的顶部对齐(前提:当前区域可流动)
// false 的话表示元素的底部与当前区域的可见部分的尾部对齐(前提:当前区域可流动)
el.scrollIntoView({
    behavior:'smooth'    //价格过渡动画(固定的)
})
//这个title-part元素将以平滑的滚动方式滚动到与视口底部齐平地方(有兼容性问题)
document.querySelector("#title-part").scrollIntoView({
    block: 'end',
    behavior: 'smooth' 
})
 
//这个article-part元素将以平滑的滚动方式滚动到与视口顶部齐平地方(有兼容性问题)
document.querySelector("#article-part").scrollIntoView({
    block: 'start',
    behavior: 'smooth'
})
 
//这个articleMU-part元素将木讷的瞬间滚动到与视口顶部齐平地方(无滚动动画效果)
document.querySelector("#articleMU-part").scrollIntoView();//默认值就是true,可以不写
 
这个titleMU-part元素将木讷的瞬间滚动到与视口底部齐平地方(无滚动动画效果)
document.querySelector("#titleMU-part").scrollIntoView(false)