万字总结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。不断获取父/子节点,触发相对应的事件。
我这个$dispatch的else写的是,如果不是这个组件的事件,我也触发了。其实应该把这句删除。只 继续往上找就可以
「使用」
// 直接这样使用就好<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