Vue的基础入门及使用

Vue的基础入门及使用

第一章 Vue核心

1.1 Vue的基本认识

1.1.1 官网

  • 英文官网:https://vuejs.org/
  • 中文官网:https://cn.vuejs.org/

1.1.2 介绍描述

  • 渐进式JavaScript框架
  • 作者:尤雨溪(一位华裔前Google工程师)
  • 作用:动态 构建用户界面

1.1.3 Vue特点

  • 1.遵循MVVM模式
    • M:Model,模型,数据对象(data)
    • V:View,视图,模板页面
    • VM:ViewModel,视图模型(Vue的实例)
  • 2.编码简洁,体积小,运行效率高,适合移动/PC端开发
  • 3.它本身只关注UI,可以轻松引入Vue插件或其他第三库开发项目

1.1.4 Vue的对象

  • el:

    • 指定dom标签容器的选择器
    • Vue就会管理对应的标签及其子标签
  • data:

    • 对象或函数类型
    • 指定初始化状态属性数据的对象
    • vm也会自动拥有data中所有属性
    • 页面中可以直接访问使用
    • 数据代理:由vm对象来代理对data中所有属性的操作(读/写)
  • methods:

    • 包含多个方法的对象
    • 供页面中的时间指令来绑定回调
    • 回调函数默认有event参数,但也可以指定自己的参数
    • 所有的方法由vue对象来调用,访问data中的属性可以直接使用this.xxx
  • computed:

    • 包含多个方法的对象
    • 对状态属性进行计算返回一个新的数据,供页面获取显示
    • 一般情况下是相当于是一个只读的属性
    • 利用set/get方法来实现属性数据的计算读取,同时监视属性数据的变化
    • 如何给对象定义get/set属性
    • 在创建对象时指定:get name(){return xxx}/set name(value) {}
    • 对象创建之后指定:Object.defineProperty(obj,age,{get(){},set(value){}})
  • watch

    • 包含多个属性监视的对象

    • 分为一般监视和深度监视

      xxx:function(value){}
      xxx:{
      	deep:true,
      	handler:fun(value)
      }
      
    • 另一种添加监视方法:vm.$watch(‘xxx’,function(value){})

1.1.5 与其他前端JS框架的关联

  • 借鉴Angular的模板数据绑定技术
  • 借鉴React的组件虚拟DOM技术

1.1.6 Vue扩展插件

  • vue-cli:vue脚手架

  • vue-resouce(axios):ajax请求

  • vue-route:路由

  • vuex:状态管理

  • vue-lazyload:图片懒加载

  • vue-scoller:页面滑动相关

  • mint-ui:基于vue的UI组件库(移动端)

  • element-ui:基于vue的UI组件库(PC端)

1.2 Vue的基本使用

1.2.1 永远的HelloWorld


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_HelloWorldtitle>
head>
<body>


<div id="test">
  <input type="text" v-model="msg"><br>
  <input type="text" v-model="msg">
  <p>Hello {{msg}}p>
div>
<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  const vm = new Vue({ // 配置对象 options
    // 配置选项(option)
    el: '#test',  // element: 选择器,指定用vue来管理页面中的哪个标签区域
    data: {
      msg: 'World'
    }
  })
script>
body>
html>

1.2.2 Vue的调试工具

Vue的基础入门及使用_第1张图片

打开Vue页面,F12进入开发者调试,选择Vue,即可使用该调试工具。

1.2.3 Vue的MVVM

Vue的基础入门及使用_第2张图片

1.3 Vue的模板语法

1.3.1 模板的理解:

  • 动态的HTML页面
  • 包含了一些JS语法代码
  • 大括号表达式
  • 指令(以v-开头的自定义标签属性)

1.3.2 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>模板语法title>
head>
<body>


<div id="app">
  <h2>1. 双大括号表达式h2>
  <p>{{content}}p>
  <p>{{content.toUpperCase()}}p>

  <h2>2. 指令一: 强制数据绑定h2>
  <a href="url">访问指定站点a><br>
  <a v-bind:href="url">访问指定站点2a><br>
  <a :href="url">访问指定站点2a><br>
  <h2>3. 指令二: 绑定事件监听h2>
  <button v-on:click="test">点我button>
  <button @click="test">点我button>
div>
<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#app',
    data: {
      content: 'NBA I Love This Game',
      url: 'http://www.baidu.com'
    },
    methods: {
      test () {
        alert('好啊!!!')
      }
    }
  })
script>
body>
html>

1.4 计算属性和监视

1.4.1 计算属性

  • 在computed属性对象中定义计算属性的方法
  • 在页面中使用{{方法名}}来显示计算的结果

1.4.2 监视属性

  • 通过VM对象的$watch()或watch配置来监视指定的属性
  • 当属性变化时,回调函数自动调用,在函数内部进行计算

1.4.3 计算属性高级

  • 通过getter/setter实现对属性数据的显示和监视
  • 计算属性存在缓存,多次读取只执行一次getter计算

1.4.5 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>计算属性和监视title>
head>
<body>

<div id="demo">
  姓: <input type="text" placeholder="First Name" v-model="firstName"><br>
  名: <input type="text" placeholder="Last Name" v-model="lastName"><br>
  
  姓名1(单向): <input type="text" placeholder="Full Name1" v-model="fullName1"><br>
  姓名2(单向): <input type="text" placeholder="Full Name2" v-model="fullName2"><br>
  姓名3(双向): <input type="text" placeholder="Full Name3" v-model="fullName3"><br>

  <p>{{fullName1}}p>
  <p>{{fullName1}}p>
div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  const vm = new Vue({
    el: '#demo',
    data: {
      firstName: 'A',
      lastName: 'B',
       fullName2: 'A-B'
    },

    // 计算属性配置: 值为对象
    computed: {
      //什么时候执行:初始化显示/相关的data属性发生变化
      fullName1 () { // 属性的get()
        console.log('fullName1()', this)
        return this.firstName + '-' + this.lastName
      },

      fullName3: {
        // 回调函数的三个属性:1.你定义的  2.你没有调用  3.但是它执行了
        // 回调函数:什么时候调用?用来做什么
        // 当获取当前属性值时自动调用, 将返回值(根据相关的其它属性数据)作为属性值
        get () {
          console.log('fullName3 get()')
          return this.firstName + '-' + this.lastName
        },
        // 当属性值发生了改变时自动调用, 监视当前属性值变化, 同步更新相关的其它属性值
        set (value) {// fullName3的最新value值  A-B23
          console.log('fullName3 set()', value)
          // 更新firstName和lastName
          const names = value.split('-')
          this.firstName = names[0]
          this.lastName = names[1]
        }
      }
    },

    watch: {
      // 配置监视firstName
      firstName: function (value) { // firstName发生了变化,相当于属性的set
        console.log('watch firstName', value)
        // 更新fullName2
        this.fullName2 = value + '-' + this.lastName
      }
    }
  })

  // 监视lastName
  vm.$watch('lastName', function (value) {
    console.log('$watch lastName', value)
    // 更新fullName2
    this.fullName2 = this.firstName + '-' + value
  })

script>
body>
html>

1.5 class与style绑定

1.5.1 理解

  • 在应用界面上,某个(些)元素的样式是变化的
  • class/style绑定就是专门用来实现动态样式效果的技术

1.5.2 class绑定

  • :class=‘xxx’
  • 表达式是字符串:‘classA’
  • 表达式是对象:{classA:isA,classB:isB}
  • 表达式是数组:[‘classA’,‘classB’]

1.5.3 style绑定

  • :style="{color:activeColor,fontSize:fontSize+‘px’}"
  • 必须是对象
  • 其中activeColor/fontSize 是data属性

1.5.4 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>class与style绑定title>
  <style>
    .classA {
      color: red;
    }
    .classB {
      background: blue;
    }
    .classC {
      font-size: 20px;
    }
  style>
head>
<body>



<div id="demo">
  <h2>1. class绑定: :class='xxx'h2>
  <p :class="myClass">xxx是字符串p>
  <p :class="{classA: hasClassA, classB: hasClassB}">xxx是对象p>
  <p :class="['classA', 'classB']">xxx是数组p>

  <h2>2. style绑定h2>
  <p :style="{color:activeColor, fontSize}">:style="{ color: activeColor, fontSize: fontSize + 'px' }"p>

  <button @click="update">更新button>

div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#demo',
    data: {
      myClass: 'classA',
      hasClassA: true,
      hasClassB: false,
      activeColor: 'red',
      fontSize: '20px'
    },

    methods: {
      update () {
        this.myClass = 'classB'
        this.hasClassA = !this.hasClassA
        this.hasClassB = !this.hasClassB
        this.activeColor = 'yellow'
        this.fontSize = '30px'
      }
    }
  })
script>
body>
html>

1.6 条件渲染

1.6.1 条件渲染指令

  • v-if与v-else
  • v-show

1.6.2 比较v-if与v-show

  • 如果需要频繁切换,v-show较好
  • 当条件不成立时,v-if的所有子节点不会解析(项目中使用)

1.6.3 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>条件渲染title>
head>
<body>


<div id="demo">
  <p v-if="ok">表白成功p>
  <p v-else>表白失败p>

  <hr>
  <p v-show="ok">求婚成功p>
  <p v-show="!ok">求婚失败p>

  <button @click="ok=!ok">切换button>
div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#demo',
    data: {
      ok: true,
    }
  })
script>
body>
html>

1.7 列表渲染

1.7.1 列表显示指令

  • 数组:v-for/index
  • 对象:v-for/key

1.7.2 列表的更新显示

  • 删除item
  • 替换item

1.7.3 列表的高级处理

  • 列表过滤
  • 列表排序

1.7.4 列表显示代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>列表渲染title>
head>
<body>



<div id="demo">
  <h2>测试: v-for 遍历数组h2>
  <ul>
    <li v-for="(p, index) in persons" :key="index">
      {{index}}--{{p.name}}--{{p.age}}
      --<button @click="deleteP(index)">删除button>
      --<button @click="updateP(index, {name:'Cat', age: 16})">更新button>
    li>
  ul>
  <button @click="addP({name: 'xfzhang', age: 18})">添加button>

  <h2>测试: v-for 遍历对象h2>

  <ul>
    <li v-for="(item, key) in persons[1]" :key="key">{{key}}={{item}}li>
  ul>

div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#demo',
    data: {
      persons: [
        {name: 'Tom', age:18},
        {name: 'Jack', age:17},
        {name: 'Bob', age:19},
        {name: 'Mary', age:16}
      ]
    },

    methods: {
      deleteP (index) {
        this.persons.splice(index, 1) // 调用了不是原生数组的splice(), 而是一个变异(重写)方法
              // 1. 调用原生的数组的对应方法
              // 2. 更新界面
      },

      updateP (index, newP) {
        console.log('updateP', index, newP)
        // this.persons[index] = newP  // vue根本就不知道
        this.persons.splice(index, 1, newP)
        // this.persons = []
      },

      addP (newP) {
        this.persons.push(newP)
      }
    }
  })
script>
body>
html>

1.7.5 列表的搜索排序


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>过滤与排序title>
head>
<body>


<div id="demo">
  <input type="text" v-model="searchName">
  <ul>
    <li v-for="(p, index) in filterPersons" :key="index">
      {{index}}--{{p.name}}--{{p.age}}
    li>
  ul>
  <div>
    <button @click="setOrderType(2)">年龄升序button>
    <button @click="setOrderType(1)">年龄降序button>
    <button @click="setOrderType(0)">原本顺序button>
  div>
div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#demo',
    data: {
      searchName: '',
      orderType: 0, // 0代表不排序, 1代表降序, 2代表升序
      persons: [
        {name: 'Tom', age:18},
        {name: 'Jack', age:17},
        {name: 'Bob', age:19},
        {name: 'Mary', age:16}
      ]
    },

    computed: {
      filterPersons () {
//        debugger
        // 取出相关数据
        const {searchName, persons, orderType} = this
        let arr = [...persons]
        // 过滤数组
        if(searchName.trim()) {
          arr = persons.filter(p => p.name.indexOf(searchName)!==-1)
        }
        // 排序
        if(orderType) {
          arr.sort(function (p1, p2) {
            if(orderType===1) { // 降序
              return p2.age-p1.age
            } else { // 升序
              return p1.age-p2.age
            }

          })
        }
        return arr
      }
    },

    methods: {
      setOrderType (orderType) {
        this.orderType = orderType
      }
    }
  })
script>
body>
html>

1.8 事件处理

1.8.1 绑定监听

  • v-on:xxx=“fun”
  • @xxx=“fun”
  • @xxx=“fun(参数)”
  • 默认事件形参:event
  • 隐含属性对象:$event

1.8.2 事件修饰符

  • .prevent:阻止事件的默认行为event.preventDefault()
  • .stop:停止事件冒泡 event.stopPropagation()

1.8.3 按键修饰符

  • .keycode:操作的是某个keycode值的键
  • .keyName:操作的是某个按键名的键(少部分)

1.8.4 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>07_事件处理title>
head>
<body>


<div id="example">

  <h2>1. 绑定监听h2>
  <button @click="test1">test1button>
  <button @click="test2('abc')">test2button>
  <button @click="test3('abcd', $event)">test3button>

  <h2>2. 事件修饰符h2>
  <a href="http://www.baidu.com" @click.prevent="test4">百度一下a>
  <div style="width: 200px;height: 200px;background: red" @click="test5">
    <div style="width: 100px;height: 100px;background: blue" @click.stop="test6">div>
  div>

  <h2>3. 按键修饰符h2>
  <input type="text" @keyup.13="test7">
  <input type="text" @keyup.enter="test7">

div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#example',
    data: {

    },
    methods: {
      test1(event) {
        alert(event.target.innerHTML)
      },
      test2 (msg) {
        alert(msg)
      },
      test3 (msg, event) {
        alert(msg+'---'+event.target.textContent)
      },

      test4 () {
        alert('点击了链接')
      },

      test5 () {
        alert('out')
      },
      test6 () {
        alert('inner')
      },

      test7 (event) {
        console.log(event.keyCode)
        alert(event.target.value)
      }
    }
  })
script>
body>
html>

1.9 表单输入绑定

1.9.1 使用v-model对表单数据自动收集

  • text/textarea 文本
  • checkbox 多选
  • radio 单选
  • select 选择

1.9.2 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>表单输入绑定title>
head>
<body>

<div id="demo">
  <form action="/xxx" @submit.prevent="handleSubmit">
    <span>用户名: span>
    <input type="text" v-model="username"><br>

    <span>密码: span>
    <input type="password" v-model="pwd"><br>

    <span>性别: span>
    <input type="radio" id="female" value="" v-model="sex">
    <label for="female">label>
    <input type="radio" id="male" value="" v-model="sex">
    <label for="male">label><br>

    <span>爱好: span>
    <input type="checkbox" id="basket" value="basket" v-model="likes">
    <label for="basket">篮球label>
    <input type="checkbox" id="foot" value="foot" v-model="likes">
    <label for="foot">足球label>
    <input type="checkbox" id="pingpang" value="pingpang" v-model="likes">
    <label for="pingpang">乒乓label><br>

    <span>城市: span>
    <select v-model="cityId">
      <option value="">未选择option>
      <option :value="city.id" v-for="(city, index) in allCitys" :key="city.id">{{city.name}}option>
    select><br>
    <span>介绍: span>
    <textarea rows="10" v-model="info">textarea><br><br>

    <input type="submit" value="注册">
  form>
div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#demo',
    data: {
      username: '',
      pwd: '',
      sex: '男',
      likes: ['foot'],
      allCitys: [{id: 1, name: 'BJ'}, {id: 2, name: 'SS'}, {id: 3, name: 'SZ'}],
      cityId: '2',
      info: ''
    },
    methods: {
      handleSubmit () {
        console.log(this.username, this.pwd, this.sex, this.likes, this.cityId, this.info)
        alert('提交注册的ajax请求')
      }
    }
  })
script>
body>
html>

1.10 Vue实例生命周期

1.10.1 生命周期流程图

Vue的基础入门及使用_第3张图片

1.10.2 vue生命周期分析

  • 1.初始化显示
    • beforeCreate()
    • created()
    • beforeMount()
    • mounted()
  • 2.更新状态:this.xxx=value
    • beforeUpdate()
    • updated()
  • 3.销毁vue实例:vm.$destory()
    • beforeDestory()
    • destoryed()

1.10.3 常用的生命周期方法

  • created()/mounted():发送ajax请求,启动定时器等异步任务
  • beforeDestory():做收尾工作,如:清除定时器

1.10.4 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>生命周期title>
head>
<body>


<div id="test">
  <button @click="destroyVue">destory vuebutton>
  <p v-if="isShow">尚硅谷IT教育p>
div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#test',
    data: {
      isShow: true
    },

    beforeCreate() {
      console.log('beforeCreate()')
    },

    created() {
      console.log('created()')
    },

    beforeMount() {
      console.log('beforeMount()')
    },

    mounted () {
      console.log('mounted()')
      // 执行异步任务
      this.intervalId = setInterval(() => {
        console.log('-----')
        this.isShow = !this.isShow
      }, 1000)
    },


    beforeUpdate() {
      console.log('beforeUpdate()')
    },
    updated () {
      console.log('updated()')
    },


    beforeDestroy() {
      console.log('beforeDestroy()')
      // 执行收尾的工作
      clearInterval(this.intervalId)
    },

    destroyed() {
      console.log('destroyed()')
    },

    methods: {
      destroyVue () {
        this.$destroy()
      }
    }
  })
script>
body>
html>

1.11 过渡&动画

1.11.1 vue动画的理解

  • 操作css的trasition或animation
  • vue会给目标元素添加/移除特定的class
  • 过渡的相关类名
    • xxx-enter-active:指定显示的transition
    • xxx-leave-action:指定隐藏的transition
    • xxx-enter/xxx-leave-to:指定隐藏时的样式
      Vue的基础入门及使用_第4张图片

1.11.2 基本过渡动画的编码

  • 在目标元素外包裹
  • 定义calss样式
    • 指定过渡样式:transition
    • 指定隐藏时的样式:opacity/其他

1.11.3 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>过渡&动画title>
  <style>
    /*指定过渡样式*/
    .xxx-enter-active, .xxx-leave-active {
      transition: opacity 1s
    }
    /*指定隐藏时的样式*/
    .xxx-enter, .xxx-leave-to {
      opacity: 0;
    }


    .move-enter-active {
      transition: all 1s
    }

    .move-leave-active {
      transition: all 3s
    }

    .move-enter, .move-leave-to {
      opacity: 0;
      transform: translateX(20px)
    }
  style>
head>
<body>




<div id="demo">
  <button @click="show = !show">Togglebutton>
  <transition name="xxx">
    <p v-show="show">hellop>
  transition>
div>

<hr>
<div id="demo2">
  <button @click="show = !show">Toggle2button>
  <transition name="move">
    <p v-show="show">hellop>
  transition>
div>


<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#demo',
    data: {
      show: true
    }
  })

  new Vue({
    el: '#demo2',
    data: {
      show: true
    }
  })

script>
body>
html>

1.12 过滤器

1.12.1 理解过滤器

  • 功能:对要显示的数据进行特定格式化后在显示
  • 注意:并没有改变原本的数据,可以产生新的对应的数据

1.12.2 定义和使用过滤器

  • 定义过滤器
Vue.filter(filterName,function(value[,arg1,arg2,....])){
// 进行一定的数据处理
return new Value
}
  • 使用过滤器
<div>{{myData|filterName}}</div>
<div>{{myData|filterName(arg)}}</div>

1.12.3 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>过滤器title>
head>
<body>


<div id="test">
  <h2>显示格式化的日期时间h2>
  <p>{{time}}p>
  <p>最完整的: {{time | dateString}}p>
  <p>年月日: {{time | dateString('YYYY-MM-DD')}}p>
div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript" src="https://cdn.bootcss.com/moment.js/2.22.1/moment.js">script>
<script>
  // 定义过滤器
  Vue.filter('dateString', function (value, format='YYYY-MM-DD HH:mm:ss') {

    return moment(value).format(format);
  })


  new Vue({
    el: '#test',
    data: {
      time: new Date()
    },
    mounted () {
      setInterval(() => {
        this.time = new Date()
      }, 1000)
    }
  })
script>
body>
html>

1.13 内置指令与自定义指令

1.13.1 常用内置指令

  • v:text:更新元素的textContent
  • v-html:更新元素的innerHTML
  • v-if:如果为true,当前标签才会输出到页面
  • v-else:如果为false,当前标签才会输出到页面
  • v-show:通过控制display样式来控制显示/隐藏
  • v-for:遍历数组/对象
  • v-on:绑定事件监听,一般简写为@
  • v-bind:强制绑定解析表达式,可以省略v-bind
  • v-model:双向数据绑定
  • ref:指定唯一标识,vue对象通过$els属性访问这个元素对象
  • v-cloak:防止闪现,与css配合:[v-cloak]{display:none}

1.13.2 自定义指令

  • 注册全局指令
Vue.directive('my-directive',function(el,binding){
    el.innerHTML = binding.value.toupperCase()
})
  • 注册局部指定
directives:{
    'my-directive':{
        bind(el,binding){
            el.innerHTML = binding.value.toupperCase()
        }
    }
}
  • 使用自定义指令
v-my-directive='xxx'

1.13.5 内置编码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>内置指令title>
  <style>
    [v-cloak] { display: none }
  style>
head>
<body>

<div id="example">
  <p v-cloak>{{content}}p>
  <p v-text="content">p>   
  <p v-html="content">p>  
  <p ref="msg">abcdp>
  <button @click="hint">提示button>
div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  new Vue({
    el: '#example',
    data: {
      content: '百度一下'
    },
    methods: {
      hint () {
        alert(this.$refs.msg.innerHTML)
      }
    }
  })
script>
body>
html>

1.13.6 自定义指令编码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>自定义指令title>
head>
<body>




<div id="test">
  <p v-upper-text="msg">p>
  <p v-lower-text="msg">p>
div>

<div id="test2">
  <p v-upper-text="msg">p>
  <p v-lower-text="msg">p>
div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript">
  // 注册一个全局指令
  // el: 指令所在的标签对象
  // binding: 包含指令相关数据的容器对象
  Vue.directive('upper-text', function (el, binding) {
    console.log(el, binding)
    el.textContent = binding.value.toUpperCase()
  })
  new Vue({
    el: '#test',
    data: {
      msg: "I Like You"
    },
    // 注册局部指令
    directives: {
      'lower-text'(el, binding) {
        console.log(el, binding)
        el.textContent = binding.value.toLowerCase()
      }
    }

  })

  new Vue({
    el: '#test2',
    data: {
      msg: "I Like You Too"
    }
  })
script>
body>
html>

1.14 自定义插件

1.14.1 说明

  • Vue插件是一个包含install方法的对象
  • 通过install方法给Vue或Vue实例添加方法,定义全局指令等

1.14.2 代码实现


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>插件title>
head>
<body>

<div id="test">
  <p v-my-directive="msg">p>
div>

<script type="text/javascript" src="../js/vue.js">script>
<script type="text/javascript" src="vue-myPlugin.js">script>
<script type="text/javascript">
  // 声明使用插件(安装插件: 调用插件的install())
  Vue.use(MyPlugin) // 内部会调用插件对象的install()

  const vm = new Vue({
    el: '#test',
    data: {
      msg: 'HaHa'
    }
  })
  Vue.myGlobalMethod()
  vm.$myMethod()

  new Object()
script>
body>
html>

第二章 Vue组件化编码

2.1 使用vue-cli创建模板项目

2.1.1 说明

  • vue-cli是vue官方提供的脚手架工具
  • github:https://github.com/vuejs/vue-cli
  • 作用:从https://github.com/vuejs-templates下载模板项目

2.1.2 创建vue项目

  • npm install -g vue-cli :全局安装vue-cli
  • vue init webpack vue_demo :当前目录下创建项目名称为vue_demo的webpack模板
  • cd vue_demo :进入vue_demo文件夹
  • npm install :安装
  • npm run serve :运行该项目
  • 访问http://localhost:8080 :项目访问地址

2.1.3 项目结构

  • build:webpack相关的配置文件夹(基本上不需要修改)
    • dev-serve.js:通过express启动后台服务器
  • config:webpack相关的配置文件夹(基本上不需要修改)
    • index.js:指定的后台服务的端口号和静态资源文件夹
  • node_modules:vue的依赖
  • src:源码文件夹
    • components:vue组件及其相关资源文件夹
    • App.vue:应用根主组件
    • main.js:应用入口js
  • static:静态资源文件夹
  • .babelrc:babel的配置文件
  • .selintignore:eslint检查忽略的配置
  • .eslintrc.js:eslint检查的配置
  • .gitignore:git版本管制忽略的配置
  • index.html:主页面的文件
  • package.json:应用包配置文件
  • README.md:应用描述说明的readme文件

2.2 项目的打包与发布

2.2.1 打包

  • npm run build

2.2.2 发布1:使用静态服务器工具包(nginx等—)

  • npm install -g serve
  • serve dist
  • 访问:http://localhost:5000
2.2.3 发布2:使用动态web服务器(tomcat)
  • 修改配置:webpack.prod.conf.js
output:{
    publicPath:'/xxx/'   //打包文件夹的名称
}
  • 重新打包
    • npm run build
  • 修改dist文件夹为项目名称:xxx
  • 将xxx拷贝到运行的tomcat的webapps目录下
  • 访问:http://localhost:8080/xxx

2.3 eslint

2.3.1 说明

  • ESLint是一个代码规范检查工具
  • 它定义了很多特定的规则,一旦你的代码违背了某一规则,eslint会作出非常有用的提示
  • 官网:http://eslint.org/
  • 基本已经替代以前的JSLint

2.3.2 ESLint提供以下支持

  • ES
  • JSX
  • style检查
  • 自定义错误和提示

2.3.3 ESLint提供以下几种校验

  • 语法错误校验
  • 不重要或丢失的标点符号,如分号
  • 没法运行到的代码块
  • 未被使用的参数提醒
  • 确保样式的统一规则,如sass或者less
  • 检查变量的命名

2.3.4 规则的错误等级有三种

  • 0:关闭规则
  • 1:打开规则,并且作为一个警告(信息打印黄色字体)
  • 2:打开规则,并且作为一个错误(信息打印红色字体)

2.3.5 相关配置文件

  • .eslintrc.js:全局规则配置文件
'rules':{
    'no-new':1
}
  • 在js/vue文件中修改局部规则
/* eslint-disable no-new*/
new Vue({
    el:'#body',
    components:{App}
})
  • .eslintignore:指令检查忽略的文件
*.js
*.vue

2.4 组件定义与使用

2.4.1 vue文件的组成(3个部分)

  • 模板页面
<template>
    页面模板
</template>
  • JS模块对象
<script>
    export default{
		data(){//模板里面只能写方法
            return:{
   
            }
        },
        methods:{},
        computed:{}.
        components:{}
	}
</script>
  • 样式
<style>
    样式定义
</style>

2.4.2 基本使用

  • 引入组件
  • 映射成标签
  • 使用组件标签
<template>
    <div>
      <img src="./assets/logo.png" alt="logo" />
      <!-- 3.使用组件标签 -->
      <HelloWorld />
    </div>
</template>

<script>
  //1.引入组件
  import HelloWorld from './components/HelloWorld.vue'
    export default {
        // 2.映射组件标签
      components:{
        HelloWorld
      }
    }
</script>
<style scoped>
</style>

2.4.3 关于标签名与标签属性名书写问题

  • 写法一:一模一样
  • 写法二:大写变小写,并用-连接

2.5 组件间通信

2.5.1 组件间通信基本原则

  • 不要在子组件中直接修改父组件的状态数据
  • 数据在哪,更新数据的行为(函数)就应该定义在哪

2.5.2 vue组件间通信方式

  • props
  • vue的自定义事件
  • 消息订阅与发布(如:pubsub库)
  • slot
  • vuex(后面单独)

2.6 组件间通信1:props

2.6.1 使用组件标签

<my-component name='tom' :age='3' :set-name='setName'></my-component>

2.6.2 定义MyComponent时

  • 在组件内声明所有的props
  • 方式一:只指定名称
props:['name','age','setName']
  • 方式二:指定名称和类型
props:{
    name:String,
    age:Number,
    setName:Function
}
  • 方式三:指定名称/类型/必要性/默认值
props:{
    name:{type:String,required:true,default:xxx}
}

2.6.3 注意

  • 此方式用于父组件向子组件传递数据
  • 所有标签属性都会成为组件对象的属性,模板页面可以直接引用
  • 问题:
    • 如果需要向非子后代传递数据,必须多层逐层传递
    • 兄弟组件间也不能直接pops通信,必须借助父组件才可以

2.7 组件间通信2:vue自定义事件

2.7.1 绑定事件监听

//方式一:通过v-on绑定
@delete_to="deleteTodo"
//方式二:通过$on()
this.$refs.xxx.$on('delete_todo',function(todo)){
                   this.deleteTodo(todo)
                   }

2.7.2 触发事件

//触发事件
this.$emit(eventName,data)

2.7.3 注意

  • 此方式只适用于子组件向父组件发送消息(数据)
  • 问题:隔代组件或兄弟组件间通信此种方式不合适

2.8 组件间通信3:消息订阅与发布

2.8.1 订阅消息

PubSub.subscribt('msg',function(msg,data){})

2.8.2 发布新消息

PubSub.publish('msg',data)

2.8.3 注意

优点:此方式可实现任意关系组件间的通信(数据)

2.8.4 事件的两个重要操作

  • 绑定事件监听(订阅消息)
    • 目标:标签元素
    • 事件名(类型):click/focus
    • 回调函数:function(event){}
  • 触发事件(发布消息)
    • DOM事件:用户在浏览器上对应的界面上做对应的操作
    • 自定义:编码手动触发

2.9 组件间通信4:slot

2.9.1 理解

此方式用于父组件向子组件传递“标签数据”

2.9.2 子组件:Child.vue

<template>
    <div>
        <slot name="xxx">不确定的标签结构1slot>
        <div>
            组件不确定的标签结构
        div>
        <slot name="yyy">不确定的标签结构2slot>
    div>
template>

2.9.3 父组件:Parent.vue

<child>
	<div slot="xxx">
        xxx对应的标签结构
    div>
    <div slot="yyy">
        yyy对应的标签结构
    div>
child>

第三章 Vue-Ajax

3.1 Vue项目中常用的2个ajax库

3.1.1 Vue-Resource

vue插件,非官方库,vue1.x使用广泛

3.1.2 axios

通用的Ajax请求库,官方推荐,vue2.x使用广泛

3.2 Vue-Resource的使用

3.2.1 在线文档

https://github.com/pagekit/vue-resource/blob/develop/docs/http.md

3.2.2 下载

npm install vue-resource --save

3.2.3 代码使用

// 引入模块
import VueResource from 'vue-resource'
// 使用插件
Vue.use(VueResource)

// 通过vue组件对象发送ajax请求
this.$http.get('/someURL').then(response)=>{
    //请求成功的数据
    console.log(response.data)//返回结果数据
},(response)=>{
    //错误信息
    console.log(response.statusText)//错误信息
}

3.3 axios的使用

3.3.1 下载

npm install axios --save

3.3.2 代码实现

// 引入模块
import axios from 'axios'

//发送Ajax请求
axios.get(url).then(response=>{
    console.log(response.data)//得到返回结果数据
}).catch(error=>{
    console.log(error.message)//错误信息
})

第四章 Vue UI组件库

4.1 常用的UI组件库

  • Mint UI:
    • 饿了么开源的基于vue的移动端UI组件库
  • Elment UI:
    • 饿了么开源的基于vue的PC端UI组件库

4.2 使用Mint UI

4.2.1 下载

npm install --save mint-ui

4.2.2 实现按需打包

// 下载
npm install --save-dev babel-plugin-component
// 修改babel配置
"plugins":["transform-runtime",["component",{
    "libraryName":"mint-ui",
    "style":true
}]]

4.2.3 mint-ui组件分类

  • 标签组件
  • 非标签组件

4.2.4 使用mint-ui

  • index.html
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimm-scale=1,user-scalable=no" />
<script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js">script>
<script>
	if('addEventListener' in document){
        document.addEventListener('DOMContentLoaded',function(){
            FastClick.attach(document.body);
        },false);
    }
    if(!window.Promise){
        document.writelv('<script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js">script>')
    }
script>
  • main.js
import {Button} from 'mint-ui'
Vue.component(Button.name,Button)
  • App.vue
<template>
	<mt-button @click="handleClick" type="primary" style="width:100%">Testmt-button>
template>
<script>
	import {Toast} from 'mint-ui'
    export default{
        methods:{
            handleClick(){
                Toast('点击了测试');
            }
        }
    }
script>

第五章 Vue-router

5.1 理解

5.1.1 说明

  • 官方提供的用来实现SPA(单页)的vue插件
  • github:https://github.com/vuejs/vue-router
  • 中文文档:http://router.vuejs.org/zh-cn/
  • 下载:npm install vue-router --save

5.1.2 相关API说明

  • VueRouter():用于创建路由器的构建函数
new VueRouter({
    //多个配置项
})
  • 路由配置
routes:[
    {//一般路由
       path:'/about',
        component:About
    },
    {//自动跳转路由
        path:'/',
        redirect:'/about'
    }
]
  • 注册路由器
import router from './router'
new Vue({
    router
})
  • 使用路由组件标签
1.<router-link>:用来生成路由链接
    <router-link to='/xxx'>Go To XXXrouter-link>
2.<router-view>:用来显示当前路由组件界面
    <router-view>router-view>

5.2 基本路由

5.2.1 路由组件

文件夹命名:pages/views

示例路由组件:Home.vue/About.vue

5.2.2 应用组件:App.vue

<div>
    
    <router-linke to="/about">Aboutrouter-linke>
div>

5.2.3 路由器模块:src/router/index.js

export default new VueRouter({
	routes:[
	{
	 path:'/',
	redirect:'/about'
	},
	{
	path:'/about',
	component:About
	},
	{
	path:'/home',
	component:Home
	}
	]
})

5.2.4 注册路由器:main.js

import Vue from 'vue'
import router from './router'
// 创建vue配置路由器
new Vue({
    el:'#app',
    router,
    render:h=>h(app)
})

5.2.5 优化路由器配置

linkActiveClass:‘active’;//指定选中的路由链接的class

5.2.6 总结:编写使用路由的3步

  • 定义路由组件
  • 注册路由
  • 使用路由

5.3.1 子路由组件

News.vue

Message.vue

5.3.2 配置嵌套路由:router.js

path:'/home',
component:hoem,
children:[
    {
        path:'/home/news',
        component:News
    },
    {
        path:'message',//简化写法	
        component:Message
    }
]

5.3.4 路由链接:Home.vue

<router-link to="/home/news">Newsrouter-link>
<router-link to="/home/message">Messagerouter-link>
<router-view>router-view>

5.4 缓存路由组件对象

5.4.1 理解

  • 默认情况下,被切换的路由组件对象会死亡释放,再次回来时是重新创建的
  • 如果可以缓存路由组件对象,可以提高用户体验

5.4.2 编码实现

<keep-alive>
	<router-view>router-view>
keep-alive>

5.5 向路由组件传递数据

5.5.1 方式1:路由路径携带参数(param/query)

  • 配置路由
children:[
    {
        path:'mdetail/:id',
        component:MessageDetail
    }
]
  • 路由路径
<router-link :to="'/home/message/mdetail/'+m.id">{{m.title}}router-link>
  • 路由组件中读取请求参数
this.$route.params.id

5.5.2 方式2:属性携带数据

5.6 编程式路由导航

相关API

  • this.$router.push(path):相当于点击路由链接(可以返回当前路由界面)
  • this.$router.replace(path):用新路由替换当前路由(不可以返回当前路由界面)
  • this.$router.back():请求(返回)上一个记录路由
  • this.$router.go(-1):请求(返回)上一个记录路由
  • this.$router.go(1):请求下一个记录路由

5.6.2 代码实现

  pushShow (id) {
      this.$router.push(`/home/message/detail/${id}`)
      }

6.1 说明

  • 分析vue作为一个MVVM框架的基本实现原理
    • 数据代理
    • 模板解析
    • 数据绑定
  • 不直接看vue.js的源码
  • 剖析github上仿vue实现的MVVM库
  • 地址:https://github.com/DMQ/mvvm

6.2 准备知识

  • [].slice.call(lis):将伪数组转换为真数组
  • node.noteType:得到节点类型
  • Object.defineProperty(obj,propName,{}):给对象添加/修改属性(指定描述符)
    • configurable:true/false 是否可以重新define
    • enumerable:true/false 是否可以枚举(for…in/keys())
    • value:指定初始值
    • writable:true/false value是否可以修改
    • get:回调函数,用来得到当前属性值
    • set:回调函数,用来监视当前属性值的变化
  • Object.keys(obj):得到对象自身可枚举的属性名的数组
  • DocumentFragment:文档碎片(高效批量更新多个节点)
  • obj.hasOwnProperty(prop):判断prop是否是obj自身的属性

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>

<div id="test">MVVMddiv>

<ul id="fragment_test">
  <li>test1li>
  <li>test2li>
  <li>test3li>
ul>


<script type="text/javascript">
  //1. [].slice.call(lis): 根据伪数组生成对应的真数组
  const lis = document.getElementsByTagName('li') // lis是伪数组(是一个特别的对象, length和数值下标属性)
  console.log(lis instanceof Object, lis instanceof Array)
  // 数组的slice()截取数组中指定部分的元素, 生成一个新的数组  [1, 3, 5, 7, 9], slice(0, 3)
  // slice2()
  Array.prototype.slice2 = function (start, end) {
    start = start || 0
    end = start || this.length
    const arr = []
    for (var i = start; i < end; i++) {
      arr.push(this[i])
    }
    return arr
  }
  const lis2 = Array.prototype.slice.call(lis)  // lis.slice()
  console.log(lis2 instanceof Object, lis2 instanceof Array)
  // lis2.forEach()

  //2. node.nodeType: 得到节点类型
  const elementNode = document.getElementById('test')
  const attrNode = elementNode.getAttributeNode('id')
  const textNode = elementNode.firstChild
  console.log(elementNode.nodeType, attrNode.nodeType, textNode.nodeType)

  //3. Object.defineProperty(obj, propertyName, {}): 给对象添加属性(指定描述符)
  const obj = {
    firstName: 'A',
    lastName: 'B'
  }
  //obj.fullName = 'A-B'
  Object.defineProperty(obj, 'fullName', {
    // 属性描述符:

    // 数据描述符

    //访问描述符
    // 当读取对象此属性值时自动调用, 将函数返回的值作为属性值, this为obj
    get () {
      return this.firstName + "-" + this.lastName
    },
    // 当修改了对象的当前属性值时自动调用, 监视当前属性值的变化, 修改相关的属性, this为obj
    set (value) {
      const names = value.split('-')
      this.firstName = names[0]
      this.lastName = names[1]
    }
  })

  console.log(obj.fullName) // A-B
  obj.fullName = 'C-D'
  console.log(obj.firstName, obj.lastName) // C D

  Object.defineProperty(obj, 'fullName2', {
    configurable: false, //是否可以重新define
    enumerable: true, // 是否可以枚举(for..in / keys())
    value: 'A-B', // 指定初始值
    writable: false // value是否可以修改
  })
  console.log(obj.fullName2)  // A-B
  obj.fullName2 = 'E-F'
  console.log(obj.fullName2) // A-B
  /*Object.defineProperty(obj, 'fullName2', {
    configurable: true,
    enumerable: true,
    value: 'G-H',
    writable: true
  })*/

  //4. Object.keys(obj): 得到对象自身可枚举属性组成的数组
  const names = Object.keys(obj)
  console.log(names)
  //5. obj.hasOwnProperty(prop): 判断prop是否是obj自身的属性
  console.log(obj.hasOwnProperty('fullName'), obj.hasOwnProperty('toString'))  // true false

  //6. DocumentFragment: 文档碎片(高效批量更新多个节点)
  // document: 对应显示的页面, 包含n个elment  一旦更新document内部的某个元素界面更新
  // documentFragment: 内存中保存n个element的容器对象(不与界面关联), 如果更新framgnet中的某个element, 界面不变
  /*
  
  • test1
  • test2
  • test3
*/
const ul = document.getElementById('fragment_test') // 1. 创建fragment const fragment = document.createDocumentFragment() // 2. 取出ul中所有子节点取出保存到fragment let child while(child=ul.firstChild) { // 一个节点只能有一个父亲 fragment.appendChild(child) // 先将child从ul中移除, 添加为fragment子节点 } // 3. 更新fragment中所有li的文本 Array.prototype.slice.call(fragment.childNodes).forEach(node => { if (node.nodeType===1) { // 元素节点
  • node.textContent = 'atguigu' } }) // 4. 将fragment插入ul ul.appendChild(fragment) script> body> html>
  • 6.3 数据代理

    • 数据代理:通过一个对象代理对另一个对象(在前一个对象内部)中属性的操作(读/写)
    • vue数据代理:通过vm对象来代理data对象中所有属性的操作
    • 好处:更方便的操作data中的数据
    • 基本实现流程
      • 通过Object.defineProperty()给vm添加与data对象的属性对应的属性描述符
      • 所有添加的属性都包含getter/setter
      • getter/setter内部去操作dta中对应的属性数据

    代码实现:

    
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>数据代理title>
    head>
    <body>
    
    
    <div id="test">div>
    
    <script type="text/javascript" src="js/mvvm/compile.js">script>
    <script type="text/javascript" src="js/mvvm/mvvm.js">script>
    <script type="text/javascript" src="js/mvvm/observer.js">script>
    <script type="text/javascript" src="js/mvvm/watcher.js">script>
    <script type="text/javascript">
      const vm = new MVVM({
        el: "#test",
        data: {
          name: '张三2'
        }
      })
      console.log(vm.name)  // 读取的是data中的name,  vm代理对data的读操作
      vm.name = '李四2' // 数据保存到data中的name上, vm代理对data的写操作
      console.log(vm.name, vm._data.name)
    script>
    body>
    html>
    

    6.4 模板解析

    6.4.1 模板解析的基本流程

    • 将el的所有子节点取出,添加到一个新建的文档fragment对象中
    • 对fragment中的所有层次子节点递归进行编译解析处理
      • 对大括号表达式文本节点进行解析
      • 对元素节点的指令属性进行解析
        • 事件指令解析
        • 一般指令解析
    • 将解析后的fragment添加到el中显示

    6.4.2 模板解析1:大括号表达式解析

    • 根据正则对象得到匹配出的表达式字符串:子匹配/RegExp.$1 name
    • 从data中取出表达式对应的属性值
    • 将属性值设置为文本节点的textContent
    
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>模板解析_表达式_vuetitle>
    head>
    <body>
    <div id="test">
      <p>{{name}}p>
    div>
    
    <script type="text/javascript" src="js/mvvm/compile.js">script>
    <script type="text/javascript" src="js/mvvm/mvvm.js">script>
    <script type="text/javascript" src="js/mvvm/observer.js">script>
    <script type="text/javascript" src="js/mvvm/watcher.js">script>
    <script type="text/javascript">
      new MVVM({
        el: '#test',
        data: {
          name: 'SADAMU'
        }
      })
    script>
    body>
    html>
    

    6.4.3 模板解析2:事件指令解析

    • 从指令名中取出事件名
    • 根据指令的值(表达式)从methods中得到对应的事件处理函数对象
    • 给当前元素节点绑定指定事件名和回调函数的dom事件监听
    • 指令解析完后,移除此指令属性
    
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>模板解析_事件指令title>
    head>
    <body>
      <div id="test">
        <button v-on:click="test">测试button>
      div>
    
      <script type="text/javascript" src="js/mvvm/compile.js">script>
      <script type="text/javascript" src="js/mvvm/mvvm.js">script>
      <script type="text/javascript" src="js/mvvm/observer.js">script>
      <script type="text/javascript" src="js/mvvm/watcher.js">script>
      <script type="text/javascript">
        new MVVM({
          el: '#test',
          data: {
            msg: 'hello atguigu'
          },
          methods: {
            test () {
              alert(this.msg)
            }
          }
        })
      script>
    body>
    html>
    

    6.4.4 模板解析3:一般指令解析

    • 得到指令名和指令值(表达式) text/html/class msg/myClass
    • 从data中根据表达式得到对应的值
    • 根据指令名确定需要操作元素节点的什么属性
      • v-text—textContent属性
      • v-html—innerHTML属性
      • v-class—className属性
    • 将得到的表达式的值设置到对应的属性上
    • 移除元素的指令属性
    
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>模板解析_一般指令title>
      <style>
        .aclass {
          color: red;
        }
        .bClass {
          font-size: 30px;
        }
      style>
    head>
    <body>
    <div id="test">
      <p v-text="msg">p>
      <p v-html="msg">p>
      <p class="bClass" v-class="myClass">xxxxxxp>
    div>
    
    <script type="text/javascript" src="js/mvvm/compile.js">script>
    <script type="text/javascript" src="js/mvvm/mvvm.js">script>
    <script type="text/javascript" src="js/mvvm/observer.js">script>
    <script type="text/javascript" src="js/mvvm/watcher.js">script>
    <script type="text/javascript">
      new MVVM({
        el: '#test',
        data: {
          msg: '尚硅谷',
          myClass: 'aclass'
        },
        methods: {
          test () {
            alert(this.msg)
          }
        }
      })
    script>
    body>
    html>
    

    6.5 数据绑定

    6.5.1 数据绑定

    一旦更新了data中的某个属性数据,所有界面上直接使用或间接使用此属性的节点更新

    6.5.2 数据劫持

    • 数据劫持是vue中用来实现数据绑定的一种技术
    • 基本思想:通过defineProperty()来监视data中所有属性(任意层次)数据的变化,有变化就去更新界面

    6.5.3 四个重要对象

    • Observer

      • 用来对data所有属性数据进行劫持的构造函数
      • 给data中所有属性重新定义属性描述(get/set)
      • 为data中的每个属性创建对应的dep对象
    • Dep(Depend)

      • data中的每个属性(所有层次)都对应一个dep对象

      • 创建的时机

        • 在初始化define data中各个属性时创建对应的dep对象
        • 在data中的某个属性值被设置为新的对象时
      • 对象的结构

        {
            id,//每个dep都有一个唯一的id
            subs//包含n个对应watcher的数组(subscribes的简写)
        }
        
      • subs属性说明

        • 当watcher被创建时,内部将当前watcher对象添加到对应的dep对象的subs中
        • 当此data属性的值发生改变时,subs中所有的watcher都会受到更新的通知,从而最终更新对应的界面
    • Compiler

      • 用来解析模板页面的对象的构造函数(一个实例)
      • 利用compile对象解析模板页面
      • 每解析一个表达式(非事件指令)都会创建一个对应的watcher对象,并建立watcher与dep的关系
      • complie与watcher的关系:一对多的关系
    • Watcher

      • 模板中每个非事件指令或表达式都对应一个watcher对象

      • 监视当前表达式数据的变化

      • 创建的时机:在初始化编译模板时

      • 对象的组成

        {
            vm,//vm对象
            exp,//对应指令的表达式
            cb,//当表达式所对应的数据发生改变的回调函数
            value,//表达式当前的值
            depIds//表达式中各级属性所对应的dep对象的集合对象
            	  //属性名为dep的id,属性值为dep
        }
        
    • 总结:dep与watcher的关系:多对多

      • data中的一个属性对应一个dep,一个dep中可能包含多个watcher(模板中有几个表达式使用到了同一个属性)
      • 模板中一个非事件表达式对应一个watcher,一个watcher中可能包含多个dep(表达式是多层的:a.b)
      • 数据绑定使用到2个核心技术
        • defineProperty()
        • 消息订阅与发布

    代码实现

    
    <html>
    <head>
      <meta charset="UTF-8">
      <title>数据劫持-数据绑定title>
      
    head>
    <body>
    
    <div id="test">
      <p>{{name}}p>
      <p v-text="name">p>
      <p v-text="wife.name">p>
      <button v-on:click="update">更新button>
    div>
    
    
    
    
    <script type="text/javascript" src="js/mvvm/compile.js">script>
    <script type="text/javascript" src="js/mvvm/mvvm.js">script>
    <script type="text/javascript" src="js/mvvm/observer.js">script>
    <script type="text/javascript" src="js/mvvm/watcher.js">script>
    <script type="text/javascript">
      new MVVM({
        el: '#test',
        data: {
          name: 'sadamu',  // dep0
          wife: { // dep1
            name: 'binbin', // dep2
            age: 18 // dep3
          }
        },
        methods: {
          update () {
            this.name = 'avatar'
          }
        }
      })
    script>
    body>
    
    html>
    
    

    6.6 MVVM原理分析

    Vue的基础入门及使用_第5张图片

    6.7 双向数据绑定

    • 双向数据绑定是建立在单向数据绑定(model=>View)的基础之上的
    • 双向数据绑定的实现流程
      • 在解析v-model指令时,给当前元素添加input监听
      • 当input的value发生改变时,将最新的值赋值给当前表达式所对应的data属性

    代码实现

    
    <html>
    <head>
      <meta charset="UTF-8">
      <title>数据双向绑定title>
    head>
    <body>
    <div id="test">
      <input type="text" v-model="msg">
      <p>{{msg}}p>
    div>
    
    <script type="text/javascript" src="js/mvvm/compile.js">script>
    <script type="text/javascript" src="js/mvvm/mvvm.js">script>
    <script type="text/javascript" src="js/mvvm/observer.js">script>
    <script type="text/javascript" src="js/mvvm/watcher.js">script>
    <script type="text/javascript">
      new MVVM({
        el: '#test',
        data: {
          msg: 'haha'
        }
      })
    script>
    body>
    html>
    
    

    第七章 Vuex

    7.1 Vuex理解

    7.1.1 vuex是什么

    • github站点:https://github.com/vuejs/vuex
    • 在线文档:https://vuex.vuejs.org/zh-cn/
    • 简单来说,对vue应用中多个组件的共享状态进行集中式的管理(读/写)

    7.1.2 状态自管理应用

    • state:驱动应用的程序源
    • view:以声明方式将state映射到视图
    • actions:响应在view上的用户输入导致的状态变化(包含n个更新状态的方法)
      Vue的基础入门及使用_第6张图片

    7.1.3 多组件共享状态的问题

    • 多个视图依赖于同一状态
    • 来自不同视图的行为需要变更同一状态
    • 以前的解决办法
      • 将数据以及操作数据的行为都定义在父组件
      • 将数据以及操作数据的行为传递给需要的各个子组件(有可能需要多级传递)
    • vuex就是用来解决这个问题的

    7.2 vuex核心概念和API

    7.2.1 state

    • vuex管理的状态对象

    • 它应该是唯一的

      const state={
          xxx:initValue
      }
      

    7.2.2 mutations

    • 包含多个直接更新state的方法(回调函数)的对象

    • 谁来触发:action中的commit(‘mutation名称’)

    • 只能包含同步的代码,不能写异步代码

      const mutations={
          yyy(state,{data1}){
              //更新state的某个属性
          }
      }
      

    7.2.3 actions

    • 包含多个事件回调函数的对象

    • 通过执行:commit()来触发mutation的调用,间接更新state

    • 谁来触发:组件中:$store.dispatch(‘action名称’,data1) //‘zzz’

    • 可以包含异步代码(定时器,ajax)

      const actions={
          zzz({commit,state},data1){
              commit('yyy',{data1})
          }
      }
      

    7.2.4 getters

    • 包含多个计算属性(get)的对象

    • 谁来读取:组件中:$store.getters.xxx

      const getters={
          mmm(state){
              return ...
          }
      }
      

    7.2.5 modules

    • 包含多个module
    • 一个module是一个store的配置对象
    • 与一个组件(包含有共享数据)对应

    7.2.6 向外暴露store对象

    export default new Vuex.Store({
        state,
        mutations,
        actions,
        getters
    })
    

    7.2.7 组件中

    import {mapState,mapGetters,mapActions} from 'vuex'
    export default{
        computed:{
            ...mapState(['xxx']),
            ...mapGetters(['mmm']),
        },
        methods:mapActions(['zzz'])
    }
    
    {{xxx}}{{mmm}}@click="zzz(data)"
    

    7.2.8 映射store

    import store from './store'
    new Vue({
        store
    })
    

    7.2.9 store对象

    • 所有用vuex管理的组件中都躲了一个属性store,它就是一个store对象
    • 属性:
      • state:注册的state对象
      • getters:注册的getters对象
    • 方法:
      定是建立在单向数据绑定(model=>View)的基础之上的
    • 双向数据绑定的实现流程
      • 在解析v-model指令时,给当前元素添加input监听
      • 当input的value发生改变时,将最新的值赋值给当前表达式所对应的data属性

    代码实现

    
    <html>
    <head>
      <meta charset="UTF-8">
      <title>数据双向绑定title>
    head>
    <body>
    <div id="test">
      <input type="text" v-model="msg">
      <p>{{msg}}p>
    div>
    
    <script type="text/javascript" src="js/mvvm/compile.js">script>
    <script type="text/javascript" src="js/mvvm/mvvm.js">script>
    <script type="text/javascript" src="js/mvvm/observer.js">script>
    <script type="text/javascript" src="js/mvvm/watcher.js">script>
    <script type="text/javascript">
      new MVVM({
        el: '#test',
        data: {
          msg: 'haha'
        }
      })
    script>
    body>
    html>
    
    

    第七章 Vuex

    7.1 Vuex理解

    7.1.1 vuex是什么

    • github站点:https://github.com/vuejs/vuex
    • 在线文档:https://vuex.vuejs.org/zh-cn/
    • 简单来说,对vue应用中多个组件的共享状态进行集中式的管理(读/写)

    7.1.2 状态自管理应用

    • state:驱动应用的程序源
    • view:以声明方式将state映射到视图
    • actions:响应在view上的用户输入导致的状态变化(包含n个更新状态的方法)

    [外链图片转存中…(img-44Q93wcS-1590936591436)]

    7.1.3 多组件共享状态的问题

    • 多个视图依赖于同一状态
    • 来自不同视图的行为需要变更同一状态
    • 以前的解决办法
      • 将数据以及操作数据的行为都定义在父组件
      • 将数据以及操作数据的行为传递给需要的各个子组件(有可能需要多级传递)
    • vuex就是用来解决这个问题的

    7.2 vuex核心概念和API

    7.2.1 state

    • vuex管理的状态对象

    • 它应该是唯一的

      const state={
          xxx:initValue
      }
      

    7.2.2 mutations

    • 包含多个直接更新state的方法(回调函数)的对象

    • 谁来触发:action中的commit(‘mutation名称’)

    • 只能包含同步的代码,不能写异步代码

      const mutations={
          yyy(state,{data1}){
              //更新state的某个属性
          }
      }
      

    7.2.3 actions

    • 包含多个事件回调函数的对象

    • 通过执行:commit()来触发mutation的调用,间接更新state

    • 谁来触发:组件中:$store.dispatch(‘action名称’,data1) //‘zzz’

    • 可以包含异步代码(定时器,ajax)

      const actions={
          zzz({commit,state},data1){
              commit('yyy',{data1})
          }
      }
      

    7.2.4 getters

    • 包含多个计算属性(get)的对象

    • 谁来读取:组件中:$store.getters.xxx

      const getters={
          mmm(state){
              return ...
          }
      }
      

    7.2.5 modules

    • 包含多个module
    • 一个module是一个store的配置对象
    • 与一个组件(包含有共享数据)对应

    7.2.6 向外暴露store对象

    export default new Vuex.Store({
        state,
        mutations,
        actions,
        getters
    })
    

    7.2.7 组件中

    import {mapState,mapGetters,mapActions} from 'vuex'
    export default{
        computed:{
            ...mapState(['xxx']),
            ...mapGetters(['mmm']),
        },
        methods:mapActions(['zzz'])
    }
    
    {{xxx}}{{mmm}}@click="zzz(data)"
    

    7.2.8 映射store

    import store from './store'
    new Vue({
        store
    })
    

    7.2.9 store对象

    • 所有用vuex管理的组件中都躲了一个属性store,它就是一个store对象
    • 属性:
      • state:注册的state对象
      • getters:注册的getters对象
    • 方法:
      • dispatch(actionName,data):分发调用action

    小结

    这篇权当是学习Vue的一个基础,更多内容,我打算做一个网站,遇到了再更新吧。

    你可能感兴趣的:(学习笔记,开发笔记)