德胜云资讯,添加一些关于程序相关的内容,仅供大家学习交流(https://www.wxclwl.com)

网站地图

搜索
德胜云咨询
前端分类 javascript CSS 正则表达式 html 前端框架 typescript Ajax
热门标签:
最新标签:

Vue万字总结Vue(包含全家桶),希望这一篇可以帮到您(一)vue 生命周期这都可以,

日期:2023/03/17 16:37作者:王俊民人气:

导读:@input 和@change 区别 一个是 聚焦的时候 一个是 失去焦点的时候。return state.age + 30。...

作者:叫我阿琛

转发链接:

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, function (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: function (el) { // 聚焦元素 el.focus() }, }) let vm = new Vue({ el: #app, // 局部指令 directives: { clickOutside: { bind(el, bindings, vNode) { el.handler = function (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, function (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 这个没有实际意义,为了美感.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; } /* 进行完之后会变成红色*/ /*这个没有实际意义,为了美感*/ .v-leave { background-color: purple; } .v-leave-active{ transition: all 2s linear; } .v-leave-to{ background-color: blue; } </style> </body> </html>

动画组

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

「区别」 使用了 transition-group

「动画名称」

enter-classenter-active-classenter-to-class (2.1.8+)leave-classleave-active-classleave-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+emitprovide+inject 单项 数据流$parent+$children 直接触发父/子类的事件$broadcast + $dispatch 自己在原型上写的$attrs+$listeners 通过所有属性和方法的集合获取$bus 类似VuexVuex 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

「官方建议」

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

这个就比较简单。类似于reactredux

// 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 = function (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 = function (eventName, ComName = , value = ) { let children = this.$children // 获取得是数组 function broadcast(children) { for (let i = 0; i < children.length; i++) { let child = children[i] 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(监听事件, function (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.js import 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

网站地图

Copyright © 2002-2022 香港德胜云网络 版权所有 | 备案号:蜀ICP备2023007363号-5

声明: 本站内容全部来自互联网,非盈利性网站仅供学习交流