Vue2.0 我的用后感笔记

146 篇文章 5 订阅

用了VUE快2年了,我的工作量还挺大,基本都在复制粘贴,只知道会用,有些点却不知道为什么要这样用,是时候该写个笔记加深下印象啦.

一.Vue相较于JQUERY 原生dom js,多页面间的数据传递, 异步数据监听等,VUE从这些繁琐的数据处理中拯救了我们,它的功劳有:

1.轻量级框架:只关注视图,构建视图的集合

2.简单易学,中文文档没有语言障碍

3.双向数据绑定,操作数据简单

4.组件化,构建单页面应该有优势

5.视图数据分离,使用数据更方便

6.虚拟DOM,原生dom操作很费性能

7.数据异步监听

8.响应式的数据在不同的页面中也能做到

二.Vue数据响应式的原理

创建实例时,遍历 data 用 Object.defineProperty() (vue3 使用 proxy)将他们转为 getter/setter,并且在内部跟踪,每个组件实例都有 watcher 程序, 属性发生变化时,会通知 watcher 重新计算,然后更新组件

三.Vue数据响应式数组的缺陷

通过下标方式修改数组数据,或者给对象增加属性,不可以触发渲染,因为Object.defineProperty 拦截不到这些操作, 大部分的数组都拦截不到, vue 内部通过重写函数的方式 解决了,数组改数据 :push,pop,shift,unshift,splice,sort,reverse

四.Vue 注意点

  • 尽量减少data中数据,因为用增加 getter 和 setter, 会收集到 watcher,data的数据越多,会影响性能.
  • v-if 和 v-for 不一起使用

原因:v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。

// 如下情况,即使100个user中之需要使用一个数据,也会循环整个数组。 
<ul>
<li
  v-for="user in users"
  v-if="user.isActive"
  :key="user.id"
>
  {{ user.name }}
</li>
  </ul>

// 正确用法 放在computed里
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
  return user.isActive
})
}
}

<ul>
<li
  v-for="user in activeUsers"
  :key="user.id"
>
{{ user.name }}
</li>
</ul>

  • v-for 尽量使用 事件代理

原因 请参考如下链接 本人也不知道这点,现在学到了【前端100问】Q94:vue 在 v-for 时给每项元素绑定事件需要用事件代理吗?为什么? - 简书

 

  • SPA(单页面应用)采用 keep-alive 缓存 意思就是打开页面无刷新,这里我在项目中用到的场景是菜单的面包屑,有数据变动的就不要用这个缓存啦。

spa应用中的路由缓存问题与解决方案_weixin_34175509的博客-CSDN博客

  • 第三方模块按需导入
  • 长列表滚动到可视区再加载
  • 图片懒加载 本人做的基本是系统 还未做到商城,疯城一般对图片要求较高,所以需要了解可阅读如下链接 Vue-Lazyload插件的用法

Vue 图片懒加载 之 Vue-Lazyload - 简书

  • 防抖节流什么是防抖节流  说实话,我用了2年,如果不是今天来复习,我还是真不知道,下面这个视频比较生动的理解

 防抖节流的目的是为了提高VUE性能

 我的使用场景

 比如父组件在深度监听子组件的对象,子组件实时接收父组件数据变化的emit (对象) 如果我的项目这个场景不使用防抖节流,你们可以想想这可怕的损耗性能,关键是我这个是个类似于做PS图一样的,数据变化非常多且快。

附上函数 及用法

/**
 * 函数节流
 * @param fn
 * @param interval
 * @returns {Function}
 * @constructor
 */
export function _throttle(fn, time) {
  let last
  let timer
  const interval = time || 200
  return function() {
    const th = this
    const args = arguments
    const now = +new Date()
    if (last && now - last < interval) {
      clearTimeout(timer)
      timer = setTimeout(function() {
        last = now
        fn.apply(th, args)
      }, interval)
    } else {
      last = now
      fn.apply(th, args)
    }
  }
}
// 防抖
export function _debounce(fn, wait) {
  const delay = wait || 200
  var timer
  return function() {
    const th = this
    const args = arguments
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(function() {
      timer = null
      fn.apply(th, args)
    }, delay)
  }
}

如何使用

    changingData_keypress: _throttle(function(val) {
      this.items[this.activeItem.id].x = this.items[this.activeItem.id].x + val.x
      this.items[this.activeItem.id].y = this.items[this.activeItem.id].y + val.y
    }, 200),
  • 使用路由懒加载,异步组件 这个未深入了解 有兴趣可以百度

五.Computed 和 Watch

computed

  1. 支持缓存,依赖的数据发生变化才会重新计算
  2. 不支持异步,当有计算属性的时候,无法监听数据变化
  3. 默认走缓存,基于依赖的响应式进行缓存,或者 父组件传递过来的props 的数据进行计算
  4. 可以使用 getter 和 setter 方法更灵活

watch

  1. 不支持缓存,数据变化 会触发响应的操作
  2. 支持异步监听,两个参数,一个是最新的值,第二个是旧值
  3. 当一个属性发生变化就做像一个的操作
  4. immediate: 立即监视, deep : 深度监视 , handle: 监听函数

使用场景:

  1. 计算 当进行计算,可以依赖缓存特性,避免每次都要计算
  2. 当需要数据变化时 执行异步,或者 开销较大时,使用 watch , 限制执行该操作的频率,得到最终结果前,设置中间状态(防抖),计算属性不行

watch 监听 tip watch只监听对象上的想监听属性,如何排除其他属性监听

// 可以 直接监听   "params.a":{...}

data() {
    return {
      params: {
        a: 1,
        b: 2,
      },
    };
  },
  mounted() {
      // 遍历所有的对象属性, 筛选出要监听的属性
    Object.keys(this.params)
      .filter((item) => {
        return item === "a";
      })
      // 遍历要监听的数组
      .forEach((item) => {
        // 用 vue 实例的 watch 开启监听
        // $watch 参数1 要监听的属性, 2 监听的处理函数, 3 配置项, 可以深度和立即监听
        this.$watch(
          (vm) => {
            vm.params[item];
          },
          this.watchFun,
          {
            deep: true,
          }
        );
      });
  },
  methods: {
    edit() {
      this.params.a = 10;
      this.params.b = 10;
    },
    watchFun() {
      console.log("对象单独属性更新");
    },
  },
  watch: {
    // params: {
    //   deep: true,
    //   handler() {
    //     console.log("更新了");
    //   },
    // },
  },

六.vue 的 hook 使用

1.清除定时器

getServeTimeSetTime() {
      // 开启定时器,五分钟获取一次服务器时间
      const timer1 = setInterval(this.handleGetServerTime, 5 * 60 * 1000)
      this.$once('hook:beforeDestroy', () => {
        clearInterval(timer1)
      })
    },

2.父组件监听子组件的声明周期函数

// 1. 用 $emit 监听
 // 父组件
  <!-- 监听子组件的 mounted 事件 -->
    <DomeChilred @changeMount="changeMount" /> // 监听处理 changeMount
    // 子组件
    mounted() {
     // 子组件声明周期 触发 就像父组件发信号
     this.$emit("changeMount", "监听成功");
    },
// 2. 使用 hook 监听 --》 缺点是不可以携带子组件的参数到父组件
 // 父组件
    <!-- 使用 hook -->
    <DomeChilred @hook:mounted="changeMount" />
     changeMount() {
          console.log("子组件触发了 mounted");
        },
 // 子组件 不用操作

七.v-if、v-show、v-html

  • v-if 懒惰的, 第一次是 false 就不加载,切换时 标签创建销毁, 在虚拟 dom 操作,开销比 v-show 大 原理: VNode 不会生成
  • v-show 直接创建 显示和隐藏都是用 css display 来控制的,直接生成,在用 display:none隐藏
  • v-html : 先移除节点下的所有节点,在 innerHTML 添加 , 可能会导致 xss 攻击里面的样式还有使用 /deep/ 穿透
    • 使用场景,v-show 适合频繁切换

八.$nextTick

  • 本质是对 js 执行原理 EventLoop 的一个应用,模拟对应的 宏/微 任务的实现,用 js 的异步 来执行 vue 的异步
  • 在下次渲染完成调用,可以获取最新的DOM元素

九.$set $delete

// 给对象或者数组添加一个响应式数据  
this.$set(obj , name , 'liu');  // 对象
this.$set(arr , 0 , 'liu') // 数组
// 删除一个响应式数据
this.$delete(arr , 0 ) // 数组
this.$delete( obj , name) // 对象

十.子组件可以修改父组件的数据吗

不可以直接修改,因为 vue 是单项数据流,直接赋值操作,会破坏数据流,可以通过 $emit 派发一个自定义事件,父组件收到后,父组件自己修改

十一.assets 和 static

相同点:资源在html中使用,都是可以的。

不同点:使用assets下面的资源,在js中使用的话,路径要经过webpack中file-loader编译,路径不能直接写。

assets中的文件会经过webpack打包,重新编译,推荐该方式。而static中的文件,不会经过编译。项目在经过打包后,会生成dist文件夹,static中的文件只是复制一遍而已。简单来说,static中建议放一些外部第三方,自己的放到assets,别人的放到static中。

注意:如果把图片放在assets与static中,html页面可以使用;但在动态绑定中,assets路径的图片会加载失败,因为webpack使用的是commenJS规范,必须使用require才可以,具体代码如下:
 

<div id="hook">
    <h3>演示钩子的组件</h3>
    <p>直接使用路径</p>
    <img src="../../assets/11.png" alt="图片加载失败" title="assets中的图片">
    <img src="../../../static/11.png" alt="图片加载失败" title="static中的图片">
    <br>
    <p>动态绑定路径</p>
    <img :src="assetsURL" alt="图片加载失败" title="assets中的图片">
    <img :src="staticURL" alt="图片加载失败" title="static中的图片">
  </div>


   data (){
      return {
        assetsURL: require('../../assets/11.png'),
        staticURL: '../../../static/11.png'
      }

十二.路由的 hash 和 history ,abstract-- 抽象模式 服务器的

  • hash
    • 在url 有 # , http 请求没有,对后端没影响,改变 hash 不会重新加载页面,对浏览器支持友好,成为 SPA(单页面)标配
    • 原理 : 监听 onhashchange() 事件
  • history
    • 没有 # 更好看,需要后端配置支持,不配置好 404
    • 分两状态 :
      • 修改历史状态: H5新增,pushState 和 replaceState
      • 切换历史状态 : forward, back, go

十三.$router 和 $route

$route 是 路由信息对象, path hash fullpath matched name

$router 是 路由实例对象 包含了 跳转方法钩子函数,push back go

十四.vuex 和 localStorage

vuex 存在 内存中, localStorage 以文件的方式存储在本地,只能存储字符串

vuex 刷新页面会丢失 localStorage 不会

十五.处理错误(和警告)的更好方法

// Vue 3
const app = createApp(App);
app.config.errorHandler = (err) => {
  alert(err);
};

// Vue 2
Vue.config.errorHandler = (err) => {
  alert(err);
};

十六.常见浏览器兼容性问题

  • *{margin:0;padding:0;}

  • 图片默认有间距 行内块 会有的 --》 float 或者 父元素 font-size:0 , 转成块元素

  • 边距重叠问题,两个相邻的都设置了 margin 边距 取最大值,使用 BFC 来清除

  • 火狐浏览器不能使用 innerText 可以使用 textContent

  • 超链接访问后 hover 不显示 解决是 按顺序, L-V-H-A 来定义

  • 火狐不支持 cursor:hand, 使用pointer

  • 添加浏览器前缀

    • 谷歌,苹果 webkit
    • ie -ms-
    • 火狐 -moz-
    • 欧朋 -o-

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值