1. 首页
  2. 技术知识

万字总结Vue(包含全家桶),希望这一篇可以帮到您(一)

作者:叫我阿琛

转发链接:https://mp.weixin.qq.com/s/ph3aUt-H4QtBgw9z-VFlHA


目录

万字总结Vue(包含全家桶),希望这一篇可以帮到您(一)本篇

万字总结Vue(包含全家桶),希望这一篇可以帮到您(二)


基础使用

以下代码均经过自己测试,可以复制直接看效果。
「注意引入Vue文件」


渲染优先级

    render>
    template>
    data的插值表达式
    {{}} 放的是表达式的时候会
    「输出结果」,内部转为函数

<!DOCTYPE html><html lang=”en”><head>    <meta charset=”UTF-8″>    <title>基本概念</title>    <script src=”vue.js”></script></head><body><h1>显示优先级</h1><ul>    <li>第一个是render 有render方法就输出render的渲染结果</li>    <li>第二个是template 有template方法就输出template的内容</li>    <li>最后一个是data,如果两者不存在 则输出data里面的插值表达式</li>    {{ }} 当这里面放的是一个表达式的时候,会输出表达式的结果 原因 会转化成一个函数 render</ul><p>指令修饰符,有好多 自己官网看</p><div id=”APP”>    {{ msg }}</div><script>  let vm = new Vue({    el: ‘#app’,    data() {      return {        msg: ‘我是data’,      }    },    template: ‘<div>我是template</div>’,    render(h) {      return h(‘div’, [‘我是render’])    },    method: {      fn(e) { // 不添加括号自动添加事件源, 添加括号 手动传入事件源        console.log(‘内部已经使用bind 绑定了this ,再次绑定也没什么用’)        console.log(this)      },    },  })</script></body></html>
v-model

v-model 实际上是一个
「语法糖」

<input type=”text” :value = ‘msg’ @input=”handleInput”><!– 实际上是上述的语法糖–><input type=”text” v-model=”msg”>
v-model 的应用

<!DOCTYPE html><html lang=”en”><head>    <meta charset=”UTF-8″>    <title>v-model</title>    <script src=”vue.js”></script></head><body><div id=”app”>    {{ msg }}    <p>@input</p>    <input type=”text” :value = ‘msg’ @input=”handleInput”>    <p>这个是@chage</p>    <input type=”text” :value = ‘msg’ @change=”handleInput”>    <p>v-model  是上面@input的语法糖</p>    <input type=”text” v-model=”msg”>    <p>@input 和@change 区别  一个是 聚焦的时候 一个是 失去焦点的时候</p>    <p>下拉列表</p>    {{ selected }}<br>    <select v-model=”selected”>        <option value=”” disabled>请选择</option>        <option value=”1″>a</option>        <option value=”2″>b</option>        <option value=”3″>c</option>    </select>    <p>下拉列表多选 这样绑定的值必须是一个列表</p>    {{ selectedMore }}<br>    <select v-model=”selectedMore” multiple>        <option value=”” disabled>请选择</option>        <option value=”1″>a</option>        <option value=”2″>b</option>        <option value=”3″>c</option>    </select>    <p>复选框</p>    {{ checked }}<br>    游泳 <input v-model=”checked” type=”checkbox” value=”游泳”>    洗澡 <input v-model=”checked” type=”checkbox” value=”洗澡”>    睡觉 <input v-model=”checked” type=”checkbox” value=”睡觉”>    <p>单选框</p>    {{ radioed }}<br>    男 <input type=”radio” value=”男” v-model=”radioed”>    女 <input type=”radio” value=”女” v-model=”radioed”>    <p>v-model 修饰符</p>    <p>{{ attr }}</p>    <input type=”number” v-model.number=”attr”>    <p>{{ attrText }}作用类似@chage</p>    <input type=”text” v-model.lazy=”attrText”>    <p>{{ attrText }} 去除空格</p>    <input type=”text” v-model.trim=”attrText”></div><script>  let vm = new Vue({    el: ‘#app’,    data() {      return {        msg: ‘我是data’,        selected:”,        selectedMore:[],        checked:[],        radioed:”,        attr:0,        attrText:”      }    },    methods: {     handleInput(e){       this.msg = e.target.value     }    },  })</script></body></html>
watch

观测值的变化 执行对应函数

三种写法:

    添加
    deep属性,表明要深度遍历
    添加
    immediate属性,表明 立即执行
    添加
    name属性,执行
    methods的这个方法

<!doctype html><html lang=”en”><head>    <meta charset=”UTF-8″>    <meta name=”viewport”          content=”width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0″>    <meta http-equiv=”X-UA-Compatible” content=”ie=edge”>    <title>Document</title></head><body><div id=”app”>    {{ msg }}    {{ name }}</div><script src=”vue.js”></script><script>  let vm = new Vue({    el: ‘#app’,    data() {      return {        msg: { a: ‘123’ },        name:’456′      }    },    methods: {      fn() {        console.log(‘这是methods’)      },    },    // 第一种    // watch:{    //   msg:{    //     handler(oldValue,newValue){    //       console.log(oldValue,newValue) // 如果是对象的不到老值    //     },    //     deep: true  // 如果是对象继续深度遍历    //   }    // }    watch: {      msg: [        // {        //   handler(oldValue, newValue) {        //     console.log(oldValue, newValue) // 如果是对象的不到老值        //   },        //   immediate: true,  // 立即执行        // },        // ‘fn’, // 不知道为什么不行      ],      name:’fn’    },  })  setTimeout(() => {    vm.msg.a = ‘456’    vm.name = ‘789’  }, 1000)</script></body></html>
computed

经常使用
get,但是还有一个
set

<!doctype html><html lang=”en”><head>    <meta charset=”UTF-8″>    <meta name=”viewport”          content=”width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0″>    <meta http-equiv=”X-UA-Compatible” content=”ie=edge”>    <title>Document</title></head><body><div id=”app”>    全选: <input type=”checkbox” v-model=”checkAll”>    <hr>    <input type=”checkbox” v-for=”check in checks” v-model=”check.check”></div><script src=”vue.js”></script><script>  let vm = new Vue({    el: ‘#app’,    data() {      return {        checks: [{ check: true }, { check: true }, { check: true }],      }    },    computed: {      checkAll: {        get() {          // 有一个不满足 返回false  并且不往下进行          return this.checks.every((item) => item.check)        },        set(newValue) {          this.checks.forEach(item => item.check = newValue)        },      },    },  })</script></body></html>
watch 和computed区别

    computed不会立马取值,用到的时候才会取值. 并且有缓存,依赖数据不改变不更新结果
    watch
    「立即执行」,会先算出来一个老值.数据变化就执行函数

filter

过滤器,将属性进行格式化后在进行展示

分为
「全局」
「局部」两种

会接受两个参数,一个是要格式化的数据,一个是格式化的规则

<!DOCTYPE html><html lang=”en”><head>    <meta charset=”UTF-8″>    <title>Title</title>    <script src=”https://unpkg.com/dayjs@1.8.21/dayjs.min.js”></script>    <script src=”vue.js”></script></head><body><div id=”app”>    <p>局部</p>    {{ timer | format1(‘YYYY:MM:DD’) }}    <p>全局</p>    {{ timer | format(‘YYYY:MM:DD’) }}</div><script>  Vue.filter(‘format’, functiоn (timer, format) {    return dayjs(timer).format(format)  })  let vm = new Vue({    el:’#app’,    data() {      return {        timer: 123456789,      }    },    filters:{      format1(timer, format){        return dayjs(timer).format(format)      }    }  })</script></body></html>
指令

同样分为
「局部」
「全局」

使用的时候 在想要使用的标签上添加
v-xxx xxx为指令名字就可以

<!DOCTYPE html><html lang=”en”><head>    <meta charset=”UTF-8″>    <title>指令</title>    <script src=”vue.js”></script></head><body><div id=”app”>    <p>自动获取焦点</p>    <input type=”text” v-focus>    <p>点击显示 日历效果</p>    <div v-click-outside=”hide”>        <input type=”text” @focus=”show”>        <div v-if=”isShow”>            日历显示 时间        </div>    </div>    <h1>指令有生命周期.有钩子</h1>    <ul>        <li>bind 绑定上的时候会执行一次</li>        <li>inserted 插入的时候</li>        <li>update 当引用数据发生变化的时候</li>        <li>componentUpdate 模板更新</li>        <li>unbind 解除绑定</li>        <li>默认写成一个函数 bind+update</li>    </ul>    <h1>指令传入三个参数的含义</h1>    <ul>        <li>el 当前元素 </li>        <li>bindings 有关指令的各个属性</li>        <li>vNode 虚拟节点</li>        <li>vNode.context Vue实例</li>    </ul></div><script>  // 全局注册指令  Vue.directive(‘focus’, {    // 当被绑定的元素插入到 DOM 中时……    inserted: functiоn (el) {      // 聚焦元素      el.focus()    },  })  let vm = new Vue({    el: ‘#app’,    // 局部指令    directives: {      clickOutside: {        bind(el, bindings, vNode) {          el.handler = functiоn (e) {            // console.log(e.target)            console.log(vNode.context)            if (!el.contains(e.target)) {              vNode.context[bindings.expression]()            }          }          document.addEventListener(‘click’, el.handler)        },        unbind(el) {          document.removeEventListener(‘click’, el.handler)        },      },    },    data() {      return {        isShow: false,      }    },    methods: {      show() {        this.isShow = true      },      hide() {        this.isShow = false      },    },  })</script></body></html>
实例属性

介绍一些常用的
「实例属性」

    $mount() 挂载,参数写要挂载的节点。如果不写,则挂载的
    $el属性上,可以手动挂载(比如写Message弹框)
    $options 获取用户写的配置
    $watch 跟watch 用法一样

<!DOCTYPE html><html lang=”en”><head>    <meta charset=”UTF-8″>    <title>实例属性</title>    <script src=”vue.js”></script></head><body><div id=”app”>    {{ msg }}</div><script>  let vm = new Vue({    // el:’#app’,    data() {      return {        msg: ‘我是data’,      }    },    template: ‘<div>我是template</div>’,    render(h) {      return h(‘div’, [‘我是render’])    },  })  vm.$mount() // 挂载 提供值了就挂载到对应的 节点上  // 不提供就挂载到$el 属性上 代表要手动挂载  console.log(vm.$el) // 获取真实节点  document.body.appendChild(vm.$el)  console.log(vm.$options) // 用户参数  console.log(vm.$watch(‘msg’, functiоn (oldValue, newValue) {    console.log(oldValue, newValue)  })) //  就是 watch  另一种写法  批量更新 只更新一次 内部有队列</script></body></html>
进阶

动画

动画分为两种,一种是
CSS动画,一种是
js动画。各位按照需求选择

因为个人推荐使用
CSS作动画,所以
JS版本就不再写出来了。有兴趣的朋友可以点击这里

「css版本」

就是把
「要做动画的DOM元素用transition包裹一下

然后记住一下6个名字,分别对应动画不同的周期

    .v-enter 进入动画时候
    .v-enter-active 进入动画过程中
    .v-enter-to 进入动画进行到最后
    .v-leave 这个没有实际意义,为了X
    .v-leave-active 离开动画过程中
    .v-leave-to 离开动画结束

<!DOCTYPE html><html lang=”en”><head>    <meta charset=”UTF-8″>    <title>动画</title>    <script src=”../vue.js”></script></head><body><div id=”app”>    <p>transiton 可以有name 属性 给改名字,这样一些 v-leave 则变成的  name-leave</p>    <transition>        <div v-show=”isShow” class=”box” style=” width: 100px;height: 100px;”>        </div>    </transition>    <button @click=”handleShow”>点我</button>    <p>transition Vue动画标签 transition-group 动画组</p></div><script>  let vm = new Vue({    el: ‘#app’,    data() {      return {        isShow: false,      }    },    methods: {      handleShow() {        this.isShow = !this.isShow      },    },  })</script><style>    .box {        background-color: red    }    /*进入动画时候的颜色*/    .v-enter {        background-color: blue;    }    /*动画过程中*/    .v-enter-active {        transition: all 2s linear;    }    /*动画进行到最后*/    .v-enter-to {        background-color: yellow;    }    /*    进行完之后会变成红色*/    /*这个没有实际意义,为了X*/    .v-leave {        background-color: purple;    }    .v-leave-active{        transition: all 2s linear;    }    .v-leave-to{        background-color: blue;    }</style></body></html>
动画组

与上一个不一样的是,这个数多组动画。

「区别」 使用了
transition-group

「动画名称」

    enter-class
    enter-active-class
    enter-to-class (2.1.8+)
    leave-class
    leave-active-class
    leave-to-class (2.1.8+)

<!DOCTYPE html><html lang=”en”><head>    <meta charset=”UTF-8″>    <title>动画</title>    <script src=”../vue.js”></script>    <link href=”https://cdn.jsdelivr.net/npm/animate.css@3.5.1″ rel=”stylesheet” type=”text/css”></head><body><div id=”app”>    <p>vue中动画组</p>    <input type=”text” v-model=”content”>    <transition-group            enter-active-class=”animated bounceInLeft”            leave-active-class=”animated bounceOutRight”    >        <li v-for=”arr in computedArr” :key=”arr”>{{ arr }}</li>    </transition-group></div><script>  let vm = new Vue({    el: ‘#app’,    data() {      return {        content:”,        arrs:[‘abc’,’basd’,’zxcw’,’awqec’,’kjea’]      }    },    methods: {      handleShow() {        this.isShow = !this.isShow      },    },    computed:{      computedArr(){        return this.arrs.filter(item => item.includes(this.content))      }    }  })</script><style>li{    width: 200px;    background-color: blue;    line-height: 35px;}</style></body></html>
组件

组件通讯(重点)

我总结了 一下,大概以下几种

    props+
    emit
    provide+
    inject 单项 数据流
    $parent+
    $children 直接触发父/子类的事件
    $broadcast +
    $dispatch 自己在原型上写的
    $attrs+
    $listeners 通过所有属性和方法的集合获取
    $bus 类似
    Vuex
    Vuex
    Vue插件

props+emit

// parents<template>    <div>        <h1>Parent</h1>        <h2>第一种</h2>        <Son :money=”money” :changMoney=”changMoney”></Son>        <p>第二中方法 click2是自己定义的名字,不是原生事件</p>        <Son :money=”money” @click2=”changMoney”></Son>    </div></template><script>  import Son from ‘./Son’  export default {    name: ‘Parent’,    data() {      return {        money: 200,      }    },    components: {      Son    },    methods: {      changMoney(value) {        this.money = value      },      changMoney2(val) {        this.money += val      },    },  }</script>// son<template>    <div>        <h1>Son</h1>        <p>子组件接收到之后,利用props 属性接受,然后可以直接使用</p>        <p>子组件可以使用父组件传递的属性和函数</p>        我是爸爸给我的钱{{ money }}        <h2>第一种</h2>                <button @click=”changMoney(500)”>改变父亲钱数</button>        <h2>第二种方法</h2>        <button @click=”change”>改变父亲钱数2</button>    </div></template><script>  export default {    props:{      money: {        type:Number,        default:100      },      changMoney:{        type:Function,        default: ()=>{}      }    },    methods:{      change(){        this.$emit(‘click2’,300)      }    }  }</script>

第一种是 传递一个属性还有一个函数,子代接收到之后,可以在使用

第二种是 利用
$emit, 直接触发
「在父级定义的函数」

「特别注意」,这个
click2「不是原生的」,你把它叫做 a , b 之类等都可以


provide+inject

「官方建议」



provide
inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。



这个就比较简单。类似于
react
redux

// parent<template>    <div>        <h1>Parent</h1>        <h1> 关于son2  跨代通讯</h1>        <Son2 @eat=”eat”></Son2>    </div></template><script>  import Son2 from ‘./Son2’  export default {    provide(){      return {parent:this}    },    name: ‘Parent’,    data() {      return {        money: 200,      }    },    components: {      Son2,    },    methods: {      eat(){        console.log(‘patent中的eat方法’)      }    },  }</script>// son2<template>    <div>        Son2        <GrandSon></GrandSon>    </div></template><script>  import GrandSon from ‘./GrandSon’  export default {    name:’Son2′,    components: {      GrandSon,    },  }</script>// grandSon<template><div>    GrandSon    <p>跨代通讯的值</p>    {{ parent.money }}    <button @click=”$parent.$emit(‘eat’)”>触发父组件的eat方法</button></div></template><script>export default {  inject:[‘parent’]}</script>

写一个
Son2的作用,就是让大家明白,隔代也是可以的。一个提供,一个接收之后就可以使用


$parent+$children

这个我就直接用上面的代码了。这个比较简单。就是通过
$parent/
$children 找到它的父/子级。然后 使用或者触发他们的属性或者方法


$broadcast + $dispatch

再次引用官方的话



$dispatch
$broadcast 已经被弃用。请使用更多简明清晰的组件间通信和更好的状态管理方案,如:Vuex。



当然,我们还是介绍一些这两个方法,各位看需要使用(小声bb一下,我觉得
Vuex真香)

// 在main.js上import Vue from ‘vue’import App from ‘./App’;/** *  找父节点触发事件 * @param eventName * @param ComName * @param Value */Vue.prototype.$dispatch = functiоn (eventName, ComName = ”, Value = ”) {  let parent = this.$parent;  while (parent) {    if (ComName && parent.$options.name === ComName) {      parent.$emit(eventName, Value)      return    } else {      parent.$emit(eventName, Value)      parent = parent.$parent    }  }}/** * 找子节点触发事件 * @param eventName * @param ComName * @param value */Vue.prototype.$broadcast = functiоn (eventName, ComName = ”, value = ”) {  let children = this.$children // 获取得是数组  functiоn broadcast(children) {    for (let i = 0; i < children.length; i++) {      let child = children
      if (ComName === child.$options.name) {        child.$emit(eventName, value)        return      } else {        if (child.$children) {          broadcast(child)        }      }    }  }  broadcast(children)}
这两个方法利用了$parent$children。不断获取父/子节点,触发相对应的事件。

我这个$dispatchelse写的是,如果不是这个组件的事件,我也触发了。其实应该把这句删除。只 继续往上找就可以

「使用」
// 直接这样使用就好<button @click=”$parent.$emit(‘eat’)”>触发父组件的eat方法</button>$attrs+$listeners

官方定义
// APP.vue<template>    <div>        <Test :a=”1″ :b=”2″ :c=”3″ :d=”4″ @click=”click”></Test>    </div></template><script>  import Test from ‘./test’  export default {    data() {      return {        msg: ‘hello’,      }    },    components: {      Test,    },    methods:{      click(){        console.log(‘我是APP中的click’)      }    }  }</script>// test.vue<template><div>    我是test    <h1>使用$attrs可以获得,但是会绑定在DOM元素上</h1>    <ul>        <li>设置 <strong>inheritAttrs:false </strong>就不会绑定了</li>        <li>当props接收后,arrts将不会显示已经被接收的</li>        {{ $attrs }}        <li>这样子代传递</li>        <button @click=”$listeners.click”>触发APP中的click</button>        <test2 v-bind=”$attrs” v-on=”$listeners”></test2>    </ul></div></template><script>    import test2 from ‘./test2’;    export default {      props:[‘a’],      name:’Test’,      inheritAttrs:false,      components:{        test2      }    }</script>//test2.vue<template>    <div>        <h1>我是test2</h1>        {{ $attrs }}        <button @click=”$listeners.click”>触发APP中的click</button>    </div></template><script>  export default {    name: ‘test2’,  }</script>
「注意」

    父级这样传递属性的过程中,会把这个属性绑定在DOM元素上,(被
    props接收的不会被绑定),可以在子类中使用
    inheritAttrs:false,来设置取消绑定
    使用得时候,直接使用
    $attrs.x/
    $listeners.x使用
    往下一代传递的时候,直接使用
    v-bind=”$attrs” v-on=”$listeners”,就可以把没有被
    props接收过的都传给下一代使用

$bus

就是挂载了一个Vue实例
// APP.vue<template>    <div>        <h1>子组件如何监听父组件的mounted</h1>        <p>组件挂载, 先挂载父组件 -》渲染子组件,子mounted -》 父mounted</p>        <p>可以实现任意组件之间的通讯,但只适合小规模的</p>        <bus></bus>    </div></template><script>  import bus from ‘./$bus使用’;  export default {    data() {      return {        msg: ‘hello’,      }    },    mounted(){      this.$bus.$emit(‘监听事件’,’hello’)    },    components: {      bus    },  }</script>// $bus使用<template><div>    bus    {{ $bus.a }}</div></template><script>  export default {    name: ‘bus’,    mounted() {      // 发布订阅模式  可以多次订阅      this.$bus.$on(‘监听事件’, functiоn (value) {        console.log(value)      })    },    beforeDestroy(){      // 解绑组件      this.$bus.$off(‘监听组件’)    }  }</script>Vuex

请往后面看
插槽

<template>    <div>        <h1>插槽</h1>        <test1>            我是标签里面的内容        </test1>        <h1>具名插槽</h1>        <p>新版写法只可以用 template</p>        <p>这里插值表达式的数据用的是父类的</p>        <test1><!–            老版本写法–><!–            <div slot=”header”>asd</div>–><!–            <div slot=”footer”>qwe</div>–>            <template v-slot:header>header {{ msg }}<br></template>            <template v-slot:footer>footer</template>        </test1>        <h1>作用域插槽</h1>        <p>这样用的是子类的数据</p>        <test1><!–            老版本写法–><!–            <div slot=”header” slot-scope=”{a,b}”>{{ a }}{{ b }}</div>–>            <template v-slot:header=”{a,b}” >{{ a }},{{ b }}</template>        </test1>    </div></template><script>import test1 from ‘./test1’;  export default {    data() {      return {        msg: ‘hello’,      }    },    components:{      test1    }  }</script>// test1<template>    <div>        <h1>我是test1</h1>        <slot></slot>        <slot name=”header” a=”1″ b=”2″></slot>        <slot name=”footer”></slot>    </div></template><script>  export default {    name: ‘test1’,  }</script>
这个比较简单,就不再多多叙述。强调一点,新老版本区别

    「新版本」只可以用
    template进心包裹
    「老版本」可以用
    div

总结

看完上面的内容可以尝试模仿写一下 element-ui的表单组件。他们使用了async-validator作为校验。
Vue

同样有一个简单版本Vue数据响应式和编译原理分析 和 模拟实战.这个版本没有用到虚拟Dom等。

虚拟dom。个人也总结了一篇帮你深入了解虚拟DOM和DOM-diff,希望能帮到各位

仅仅是一个简单的实现。但是实现了 「部分指令」

完整部分(即这次总结的,带上虚拟dom等等),这个内容由于太多(标题细分太多。不好去寻找)。我另写了一篇文章,还在整理中,1号大概可以放出来。

「贴一个图证明一下。实在是考虑的太多,所以写出来比较慢」

UTOOLS1593399637478.png
vueX

推荐一下自己的另一篇文章Vuex的简单实现,感觉这一篇写的相对简单一点
Vuex 用法

这个就不多做解释了。不太熟练的朋友可以先去看官方文档

给出一下我的数据定义
// store/index.jsimport Vue from ‘vue’// import Vuex from ‘vuex’import Vuex from ‘./../vuex2’Vue.use(Vuex)const store = new Vuex.Store({  state: {    age: 10  },  strict: true,  getters: {    myAge(state) {      return state.age + 30    }  },  mutations: {    // 同步更改state  在严格模式下不可以使用异步    change(state, payload) {      state.age += payload    }  },  actions: {    // 异步更改state    asyncChange({ commit }, payload) {      setTimeout(()=>{        commit(‘change’, payload)      }, 1000)    }  }})export default store
本篇未完结,请见下一篇
作者:叫我阿琛
转发链接:https://mp.weixin.qq.com/s/ph3aUt-H4QtBgw9z-VFlHA

原创文章,作者:starterknow,如若转载,请注明出处:https://www.starterknow.com/126428.html

联系我们