Vue复习(更新中...)

官方帮助文档:

介绍 — Vue.js

MVVM:双向数据绑定

        页面输入改变数据,数据改变影响页面数据展示与渲染

        M(model):普通的javascript数据对象

        V(view):前端展示页面

        VM(ViewModel):用于双向绑定数据与页面,对于我们的课程来说,就是vue的实例

        VM就是 [视图模型] ,它做了两件事:事件监听,数据绑定

<!-- 引入vue.js类库 -->
<script src="./js/vue.js"></script>

<!-- 指定vue要去解析的模板挂载点 -->
<div id="app">
  <!-- 渲染视图,解析指定变量,让它成功你声明的数据 -->
  <h3>{{ msg }}</h3>
  <hr>
  <!-- 动态绑定数据 -->
  <input type="text" v-model="msg">
</div>

<script>
  // 实例化Vue
  const vm = new Vue({
    // 指定解析挂载点  document.querySelector
    el: '#app',
    // 声明一个变量
    // 指定数据源 vue2中数据在new Vue中可以写对应也可以写函数,在Vue3中只能写函数
    data(){
      return {
      msg: '你好Vue'
      }
    }
  })
</script>

插件

谷歌商店,搜vue devtools,第二个

https://chrome.google.com/webstore?utm_source=chrome-ntp-icon

 或 极简插件

极简插件_Chrome扩展插件商店_优质crx应用

在vscode中安装插件 vetur (工程化有提示)


双向绑定原理 / MVVM实现

实现 视图模型 必须要用到 ES5 中的 Object.defineProperty (vue2) 或者是 ES6 提供的 Proxy (vue3) .这两个都能做到 数据劫持.

Object.defineProperty() - JavaScript | MDN

 defineProperty和Proxy的区别

defineProperty和Proxy的区别_tby_pr的博客-CSDN博客


冻结对象

 冻结对象1. freeze

let target = { id: 100 }
// 冻结对象 对象就没有办法修改了
target = Object.freeze(target)
target.id = 200

冻结对象2. Object.defineProperty 的 writable:false

当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。 默认为 false。

let target = {}
Object.defineProperty(target, 'id', {
  value:100,
  writable :false
});
target.id = 200

实现mvvm(第一版)只能修改一个数据msg

<div id="app">
  <h3 v-text="msg"></h3>
  <h3 v-text="age"></h3>
  <hr>
  <input type="text" v-model="msg">
</div>

<script>
  var data = {
    msg: '你好mvvm',
    age: 20
  }

  // let target = { id: 100 }
  // 冻结对象 对象就没有办法修改了
  // target = Object.freeze(target)
  // target.id = 200

  let target = {}

  // 劫持当前的对象
  // defineProperty 它只能对对象中的属性进行劫持,不能劫持数组
  Object.defineProperty(target, 'msg', {
    // 获取器
    get() {
      console.log('get')
      return data.msg
    },
    // 修改器
    set(newV) {
      if (newV != data.msg) {
        console.log('set')
        data.msg = newV
        compileRender()
      }
    }
  });

  Object.defineProperty(target, 'age', {
    // 获取器
    get() {
      console.log('get')
      return data.age
    },
    // 修改器
    set(newV) {
      if (newV != data.age) {
        console.log('set')
        data.age = newV
        compileRender()
      }
    }
  });

  compileRender()


  function compileRender() {
    // 模板编译
    // 文本
    document.querySelectorAll(`[v-text]`).forEach(node => {
      // 要去数据源中查找的数据key
      let key = node.getAttribute('v-text')
      let value = target[key] || 0
      node.innerHTML = value
    })
    // 输入框
    document.querySelectorAll(`[v-model]`).forEach(node => {
      let key = node.getAttribute('v-model')
      let value = target[key] || 0
      node.value = value
      // 绑定一个事件
      node.addEventListener('input', function () {
        target[key] = this.value.trim()
      })
    })
  }
</script>

实现mvvm(第二版)封装

数据为两层以上时需要递归 : 优化方案==>数据扁平化.

<div id="app">
  <h3 v-text="msg"></h3>
  <h3 v-text="age"></h3>
  <hr>
  <input type="text" v-model="msg">
</div>

<script>
  var data = {
    msg: '你好mvvm',
    age: 20,
    // 不推荐数据有层级嵌套
    user: { id: 1 },
    // 数据扁平化,优化,不用递归了
    user_id: 1,
    user_name: 'aa'
  }

  // 数据劫持
  observe(data)

  // 模板编译
  compileRender(data)

  function observe(target) {
    // 只劫持json对象
    if (Object.prototype.toString.call(target) != '[object Object]') return;
    // 遍历
    for (let key in target) {
      defineRactive(target, key, target[key])
    }
  }

  function defineRactive(target, key, value) {
    observe(value)
    /* if (Object.prototype.toString.call(value) == '[object Object]') {
      observe(value)
      return;
    } */
    // 劫持当前的对象
    // defineProperty 它只能对对象中的属性进行劫持,不能劫持数组
    Object.defineProperty(target, key, {
      // 获取器
      get() {
        console.log('get')
        return value
      },
      // 修改器
      set(newV) {
        if (newV != value) {
          console.log('set')
          value = newV
          // 通知模板编译一下
          compileRender(target)
        }
      }
    });
  }

  function compileRender(target) {
    // 模板编译
    // 文本
    document.querySelectorAll(`[v-text]`).forEach(node => {
      // 要去数据源中查找的数据key
      let key = node.getAttribute('v-text')
      let value = target[key] || 0
      node.innerHTML = value
    })
    // 输入框
    document.querySelectorAll(`[v-model]`).forEach(node => {
      let key = node.getAttribute('v-model')
      let value = target[key] || 0
      node.value = value
      // 绑定一个事件
      node.addEventListener('input', function () {
        target[key] = this.value.trim()
      })
    })
  }
</script>

封装--小型Vue

=> mvvm(第三版)

封装--小型Vue_tby_pr的博客-CSDN博客


插值表达式

# 支持写法  {{变量、js表达式、三目运算符、方法调用等}}


指令 ==> v- 前缀

就是vue给html标签提供的一些自定义属性,这样属性都是带有 v- 前缀的特殊属性

指令作用:操作dom

v-html 解析html指令  

        v-html它就是不转义输出 指令

        v-html一般用它来对于后台添加的富文本内容进行展示所用,用它一定要小心

        注:尽量避免使用,容易造成危险 (XSS跨站脚本攻击)

v-text 输出文本信息   

        解决有的时候,模板解析过慢会有{{}}闪现问题,用属性不会有闪现

v-once指令

        只渲染元素和组件一次,之后元素和组件将失去响应式功能

v-if和v-show

<!-- 
  v-if
  true:显示
  false:隐藏
  false时它会把dom删除掉
  如果你是后台管理菜单建议用v-if,没有可能性来回切换
  v-if初始性能好,切换性能稍差一些
  -->
<h3 v-if="n>10">显示内容 -- if</h3>
<!-- 
  v-show
  true:显示
  false:隐藏
  false时会把dom通过css给隐藏起来
  如果你是频繁的切换操作,建议使用v-show
  v-show初始性能稍差,切换性能好一些
  -->
<h3 v-show="n>10">显示内容 -- show</h3>
<!-- 
  多分支 标签之间只能是多分支,不能有别的
  v-if v-else-if v-else
  -->
<div v-if="n<10">儿童</div>
<div v-else-if="n<20">少年</div>
<div v-else>成年</div>

v-bind指令  // 简写 : 


v-for

<!-- 指定vue要去解析的模板挂载点 -->
<div id="app">
  <!-- 
    数组循环 
    v-for="(数组元素,索引) in 数据" :key='唯一不重复的'
    v-for="(数组元素,索引) of 数据" :key='唯一不重复的'
    key是vue进行dom比对时的依据,有它则提升性能,没有也可以,但是性能比较低,不写会警告
    key不要用循环中的index索引,索引有塌陷问题
    如果你和后端合作时,一定要求后台给你的数据中有一个唯一不变化值(id)
    在vue2.x时如果你的v-if和v-for在一个标签写,v-for优先于v-if  
    template标签 它可以写v-if或v-for,但它还会编译生成html
    vue3.x中v-if优先级高于v-for
  -->
  <ul>
    <template v-if="n>=2">
      <li v-for="(item,index) in arr" :key="item">{{index}} -- {{item}}</li>
    </template>
    <template v-else>
      <li>数据加载中...</li>
    </template>
  </ul>
  <!-- 
    循环对象  vue对于 for of进行增强,它可以循环对象了
    v-for="(元素,key,index) in obj" :key="唯一值"
    v-for="(元素,key,index) of obj" :key="唯一值"
    -->
    <div v-for="(item,key,index) in obj">
      {{index}} --- 
      {{key}} --- 
      {{item}}
    </div>
</div>

<script>
  // 实例化Vue
  const vm = new Vue({
    el: '#app',
    data: {
      n: 1,
      arr: [1, 2, 3, 4, 5, 6],
      obj: { id: 1, name: '张三' }
    }

  })
</script>

v-on  // 简写 @

<div id="app">
  <!-- 
    vue中绑定事件 v-on:事件类型="方法"  v-on简写 @
    方法可以不写小括号
    绑定的方法可以定义在data或methods方法中,但是data中不建议去定义,data数据劫持
    如果不写小括号,vue把自动把event对象给传入参中,不写小括号事件没有办法传参数
    如果你小括号,vue不会自动把event对象传给入参,需要手动传入,提供【$event】变量,
    有小括号传参数就很方便
  -->
  <!-- username这不是button标签默认属性,自定义属性,获取时一定要用getAttribute -->
  <!-- <button username='张三' v-on:click="fn">点击事件</button> -->
  <!-- html5中提供dataset对象 -->
  <button data-username='张三' v-on:click="fn">点击事件</button>
  <!-- <button v-on:click="fn($event,1,2,3)">点击事件</button> -->
  <hr>
  <!-- <input type="text" v-model='todo' @keyup.enter.ctrl="onenter"> -->
  <!-- <input type="text" v-model='todo' @keyup.ctrl.90.prevent="onenter"> -->
  <input type="text" v-model='todo' @keyup.ctrl.zzz="onenter">
</div>

<script>
  Vue.config.keyCodes = {zzz:90}
  // 实例化Vue
  const vm = new Vue({
    el: '#app',
    data: {
      msg: '你好Vue',
      todo: ''
    },
    methods: {
      /* fn(ev, ...args) {
        console.log('fn', ev, args)
      } */
      fn(ev) {
        // console.log(ev.target.getAttribute('username'))
        console.log(ev.target.dataset.username)
      },
      onenter(ev) {
        // console.log(ev.keyCode == 13)
        // console.log(this.todo)
        console.log(ev.keyCode)
      }
    }

  })
</script>

绑定事件监听器(事件绑定)

# 绑定好事件实现方法后需要在Vue对象中的methods对象中实现对应的绑定方法

methods: {

    functionName(arg1,arg2,arg3,...){

        // something to do

    },

    ....

}

事件处理函数传参 -- 事件对象--- event对象

<!-- 事件处理函数调用:直接写函数名 -->

<button @click="say"></button>

<!-- 事件处理函数调用:常规调用 -->

<button @click="say($event)"></button>

# 注:如果没有参数时,可以不写小括号,默认就会把event事件对象绑定到实现的方法中,如果需要传参数时,则通过 $event 来手动传递到实现的方法中

事件修饰符

用来处理事件的特定行为

<!-- 阻止冒泡 -->

<button @click.stop="doThis"></button>

<!-- 阻止默认行为 -->

<a @click.prevent="doThis"></a>

<!-- 只执行一次 -->

<div @click.once="incr()">自增一下</div>

<!-- 绑定的元素本身触发时才触发回调 -->

<ul @click.self="incr()">

<li>你好世界</li>

</ul>

<!--  串联修饰符 -->

<button @click.stop.prevent="doThis"></button>

按键修饰符

在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符。

<!-- 只有在 `key` 是 `Enter` 回车键的时候调用 -->

<input @keyup.enter="submit">

<!-- Ctrl + Click -->

<div @click.ctrl="doSomething">Do something</div>

你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名:

// 可以使用 `v-on:keyup.f1`

Vue.config.keyCodes = {f2:113}

<input @keyup.f2="add()" value="aaaa">


样式绑定

1. class样式处理(对象)

    => 如果为true时,样式生效,如果为false不生效

    => 对象动态绑定样式,一般用于开关操作,不建议去追加样式操作

<style>
  .active {
    color: red;
  }
  .f20 {
    font-size: 50px;
  }
</style>

<!-- 指定vue要去解析的模板挂载点 -->
<div id="app">
  <!-- 对象动态绑定样式,一般用于开关操作,不建议去追加样式操作 -->
  <h3 :class="activeClass">样式为高亮</h3>

  <button @click="toggle">切换</button>
</div>

<script>
  // 实例化Vue
  const vm = new Vue({
    el: '#app',
    data: {
      // 它的数据引用类型,劫持引用(栈)
      activeClass: { active: true }
    },
    methods: {
      toggle() {
        this.activeClass.active = !this.activeClass.active
        // 修改(堆)中的数据,引用不会改变,劫持就不会知道
        // this.activeClass.f20 = true
        // Vue提供的 , 动态给对象添加属性,有劫持不到的情况 $set
        // this.$set(this.activeClass, 'f20', true)
        // 深复制 引用地址发现改变
        this.activeClass = { ...this.activeClass, f20: true }
        // this.activeClass = Object.assign({}, this.activeClass, { f20: true })
      }
    }

  })
</script>

2. class样式处理(数组)

    => 数组绑定样式,不建议有开关操作,只做追加

    => Object.defineProperty它不支持劫持数组

    => 针对于数组,vue提供了常用的7个数组方法进行升级(变异/变更) 这7方法的操作会让视图重新渲染

    => pop shift push unshift sort splice reverse

<div id="app">
  <!-- 
    数组绑定样式,不建议有开关操作,只做追加
    -->
  <h3 :class="activeArr">样式为高亮</h3>
  <button @click="addClass">追加样式</button>
</div>

<script>
  // 实例化Vue
  const vm = new Vue({
    el: '#app',
    data: {
      activeArr: ['active']
    },
    methods: {
      // Object.defineProperty它不支持劫持数组
      // 针对于数组,vue提供了常用的7个数组方法进行升级(变异/变更) 
      // 这7方法的操作会让视图重新渲染
      // pop shift push unshift sort splice reverse
      addClass() {
        this.activeArr.push('f20')
      }
    }
  })
</script>

3. 绑定style

  • 对象语法
<div :style="{color: redColor, fontSize: '20px'}">对象写法</div>
data: {
	redColor: 'red'
}
  • 数组语法
<div v-bind:style="[color, fontSize]">数组写法</div>
data: {
	color: {
		color: 'red'
	},
	fontSize: {
		'font-size': '20px'
	}
}

v-model

定义: v-model就是它们语法糖

<input type="text" :value='msg' @input='setValue'>

<input type="text" v-model="msg">

作用: 表单元素的绑定,实现了双向数据绑定,通过表单项可以更改数据。

绑定多行文本框 textarea

注意:多行文本框中使用插值表达式 无效

<div id="app">
  <div v-html="showBody()"></div>
  <!-- 多行文本使用v-model -->
  <textarea v-model="body"></textarea>
</div>

<script>
  // 实例化Vue
  const vm = new Vue({
    el: '#app',
    data: {
      body: ''
    },
    methods: {
      showBody() {
        // 正则判断替换 换行
        return this.body.replace(/(\r\n|\n)/g, '<br />')
      }
    }
  })
</script>

绑定多个复选框/全选多选  => 数组

<div id="app">
  <input type="checkbox" v-model="all" @change="allfn">全选
  <hr>
  <ul>
    <li v-for="(item,index) in source" :key="item">
      <span>
        <input type="checkbox" :value="item" v-model="lessons" @change='selectFn'>
      </span>
      <span>{{item}}</span>
      <span @click="del(index)">删除</span>
    </li>
  </ul>
</div>

<script>
  // 实例化Vue
  const vm = new Vue({
    el: '#app',
    data: {
      all: false,
      source: ['html', 'css', 'js', 'vue'],
      lessons: []
    },
    methods: {
      allfn() {
        if (this.all) {
          this.lessons = this.source
        } else {
          this.lessons = []
        }
      },
      selectFn(ev) {
        // if (ev.target.checked) {// 勾选中时
        this.all = this.lessons.length == this.source.length
        // }
      },
      del(index) {
        // 变更方法
        // this.source = this.source.filter((item, i) => i != index)
        confirm('真的要删除') && this.source.splice(index, 1)
      }
    }
  })
</script>

绑定单选框/下拉框

 修饰符

.lazy    失去焦点时触发(延时更新数据源)

.number  输入值转为数值类型

.trim    自动过滤用户输入的首尾空白字符


案例vue--简易购物车

案例vue--简易购物车_tby_pr的博客-CSDN博客


封装--localStorage本地化存储[持久化]

封装--localStorage本地化存储_tby_pr的博客-CSDN博客


案例--vue_todolist 

 案例--vue_todolist_tby_pr的博客-CSDN博客


Vue自定义指令

Vue自定义指令_tby_pr的博客-CSDN博客

 封装--vue自定义组件表单项验证

封装--vue自定义组件表单项验证_tby_pr的博客-CSDN博客

封装 -- vue自定义修饰符

封装 -- vue自定义修饰符_tby_pr的博客-CSDN博客

案例 -- vue自定义指令 实现 按钮权限

案例 -- vue自定义指令 实现 按钮权限_tby_pr的博客-CSDN博客


计算属性 - computed

是基于它们的响应式依赖进行缓存的.

计算属性定义在Vue对象中,通过关键词computed属性对象中定义一个个函数,并返回一个值,使用计算属性时和data中的数据使用方式一致

<div id="app">
  <h3>{{n1+n2}}</h3>
  <h3>{{sum()}}</h3>
  <h3>{{sum()}}</h3>
  <h3>计算属性:{{total}}</h3>
  <h3>计算属性:{{total}}</h3>
</div>

<script>
  const vm = new Vue({
    el: '#app',
    data: {
      n1: 1,
      n2: 2
    },
    computed: {
      // 此计算属性依赖于n1和n2的值,只有它俩发生了改变则,计算会重新计算
      total() {
        console.log('total')
        return this.n1 + this.n2
      }
    },
    methods: {
      // 方法计算的结果没有缓存,如果重复调用,则会执行N次
      sum() {
        console.log('sum')
        return this.n1 + this.n2
      }
    }
  })
</script>

计算属性其实是可以改变数据的/计算属性改值(工作用不到,面试可能问)

    => 标准写法

        + set

computed: {
  /* totalPrice() {
    return this.carts.reduce((p, item) => p += item.price * item.num, 0)
  } */
  // 标准写法
  totalPrice: {
    get() {
      return this.carts.reduce((p, item) => p + item.price * item.num, 0)
    },
    set(v) {
      console.log(v)
      this.n = v
    }
  }
},

侦听器 -- watch

 用侦听器做表单项验证

<div id="app">
  <input type="text" v-model='num'>
  <span>{{num_msg}}</span>
</div>

<script>
  const vm = new Vue({
    el: '#app',
    data: {
      num: '10',
      num_msg: ''
    },
    // 侦听器  1对1  依赖项只有一个
    watch: {
      num(newValue, oldValue) {
        // [^] =>写在中括号中,表示取反,不是0-9的数据则匹配成功
        if (/[^0-9]/.test(newValue)) {
          this.num_msg = '全数字'
        } else {
          this.num_msg = ''
        }
      },

// 默认不会对于引用类型进行监听,除非你修改了引用地址

// 监听对象中的具体字段的值的变化  // 'user.name'(newValue,oldValue){}

监听对象的标椎版本

// 标准版本
user: {
  // 深度监听
  deep: true,
  handler(n, o) {
    console.log(n)
  }
}

过滤器 - filters(vue3中没有)

在数据被渲染之前,可以对其进行进一步处理

除了 组件 是局部定义的,其他基本都是 全局定义 的.

案例: 超过几个变成...

<div id="app">
  <!-- 过滤器 -->
  <h3>{{title | substr(2)}}</h3>
  <h3>{{title | substr}}</h3>
</div>

<script>
  // 全局过滤器
  Vue.filter('substr', (value, len = 10) => {
    if (value.length <= len) return value;
    return value.substr(0, len) + '...'
  })

  const vm = new Vue({
    el: '#app',
    data: {
      title: '这段时间娱乐圈可谓是抢占了头条,抖音,相继出现'
    }
  })
</script>

封装 -- 对象合并

封装 -- 对象合并_tby_pr的博客-CSDN博客


混入(工作不用,因为乱)   // 就是对象合并

全局混入!

 

!!!!  可以通过全局混入的方式,给东西塞到当前实例对象里面去,想在任何地方用都能用,方便其他人去用,通过自定义属性对当前实例添加了自定义属性

局部混入

    // 混入vue配置选项中的大部份配置,只有el不能混

    // 混入时 data配置选项一定要是函数方式,且函数一定要返回一个对象

 

// 数据如果本组件中有配置则以本组件为主

 

 !!! 方法(函数)是 合并,属性值 是以 本组件 为主进行 覆盖 


Vue生命周期

在 模板编译 和 数据劫持 的 过程 暴露了一些 钩子!

vue3放弃了el,直接用$mount()

Vue生命周期_tby_pr的博客-CSDN博客


网络请求写在哪

created     beforeMount     mounted

都可以写网络请求,但是mounted是属于真实dom已经渲染,页面结构已经出来了,然后进行的网络请求,用户知道已经打开了,推荐使用。

在虚拟dom进行网络请求,会在请求后再渲染,页面是大白板,网络请求要是慢的话,用户会觉得是网速慢,就F5刷新了,无形中负载变高了。

beforeUpdate和updated也能写,但是不能改变数据源。

销毁里写就是完全没意义。


网络请求

网络请求(vue)_tby_pr的博客-CSDN博客


Vue组件


Vue插槽!!!--(封装组件使用)

Vue插槽_tby_pr的博客-CSDN博客


Vue工程化!!!***

Vue工程化_tby_pr的博客-CSDN博客


Vue路由!!!***

Vue路由_tby_pr的博客-CSDN博客


 Vue代码 异步懒加载 和 拆分

Vue代码 异步懒加载 和 拆分_tby_pr的博客-CSDN博客


Vue @占位符的代码提示

Vue @占位符的代码提示_tby_pr的博客-CSDN博客


案例 -- web移动端项目(vue)

案例 -- web移动端项目(vue)_tby_pr的博客-CSDN博客


  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值