100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 学好vue靠他就行了——vue脚手架 自定义事件 插槽等复杂内容

学好vue靠他就行了——vue脚手架 自定义事件 插槽等复杂内容

时间:2022-06-12 01:03:16

相关推荐

学好vue靠他就行了——vue脚手架 自定义事件 插槽等复杂内容

博主主页:追求~

本文承接上一篇:

学好vue靠他就行了—vue基础知识与原理(一)

学好vue靠他就行了—vue基础知识与原理(二)

希望各位博主多多关注

文章目录

2. vue脚手架,自定义事件,插槽等复杂内容2.1 脚手架脚手架文件结构脚手架demorender函数修改脚手架的默认配置脚手架中的index.html2.2 vue中的一些属性ref属性props配置项mixin(混入)插件scoped样式总结TodoList案例2.3 浏览器本地存储CookieSessionLocalStorageSessionStorage2.4 组件自定义事件2.5 全局事件总线2.6 消息订阅与发布2.7 nextTick2.8 Vue封装的过度与动画2.9 vue脚手架配置代理方法一方法二2.10 slot插槽

2. vue脚手架,自定义事件,插槽等复杂内容

2.1 脚手架

使用前置:

第一步(没有安装过的执行):全局安装 @vue/cli

npm install -g @vue/cli

第二步:切换到要创建项目的目录,然后使用命令创建项目

vue create xxxxx

第三步:启动项目

npm run serve

脚手架文件结构

├── node_modules ├── public│ ├── favicon.ico: 页签图标│ └── index.html: 主页面├── src│ ├── assets: 存放静态资源│ │ └── logo.png│ │── component: 存放组件│ │ └── HelloWorld.vue│ │── App.vue: 汇总所有组件│ │── main.js: 入口文件├── .gitignore: git版本管制忽略的配置├── babel.config.js: babel的配置文件├── package.json: 应用包配置文件 ├── README.md: 应用描述文件├── package-lock.json:包版本控制文件

脚手架demo

components:

就直接把单文件组件的 School.vue 和 Student.vue 两个文件直接拿来用,不需要修改。

App.vue:

引入这两个组件,注册一下这两个组件,再使用。

<template><div id="app"><img alt="Vue logo" src="./assets/logo.png"><Student></Student><School></School></div></template><script>import School from './components/School.vue'import Student from './components/Student.vue'export default {name: 'App',components: {School,Student}}</script><style>#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;}</style>

main.js:

入口文件

import Vue from 'vue'import App from './App.vue'Vue.config.productionTip = falsenew Vue({render: h => h(App),}).$mount('#app')

接下来就要详细讲解 main.js 中的 render 函数

render函数

回到 render 函数

之前的写法是这样:

import App from './App.vue'new Vue({el:'#root',template:`<App></App>`,components:{App},})

如果这样子写,运行的话会引发如下的报错

报错的意思是,是在使用运行版本的 vue ,没有模板解析器。

从上面的小知识可以知道,我们引入的 vue 不是完整版的,是残缺的(为了减小vue的大小)。所以残缺的vue.js 只有通过 render 函数才能把项目给跑起来。

来解析一下render

// render最原始写的方式// render是个函数,还能接收到参数a// 这个 createElement 很关键,是个回调函数new Vue({render(createElement) {console.log(typeof createElement);// 这个 createElement 回调函数能创建元素// 因为残缺的vue 不能解析 template,所以render就来帮忙解决这个问题// createElement 能创建具体的元素return createElement('h1', 'hello')}}).$mount('#app')

因为 render 函数内并没有用到 this,所以可以简写成箭头函数。

new Vue({// render: h => h(App),render: (createElement) => {return createElement(App)}}).$mount('#app')

再简写:

new Vue({// render: h => h(App),render: createElement => createElement(App)}).$mount('#app')

最后把createElement换成 h 就可以了。

对象内写方法最原始的:

let obj = {name: 'aaa',work: function (salary) {return '工资' + salary;}}

ES6 简化版:

let obj = {name: 'aaa',work(salary) {return '工资' + salary;}}

箭头函数简化版:

let obj = {name: 'aaa',work: (salary) => {return '工资' + salary;}}

箭头函数再简化(最终版):

// 只有一个参数就可以把圆括号去了,函数体内部只有一个 return 就可以把大括号去掉,return去掉let obj = {name: 'aaa',work: salary => '工资' + salary;}

这样就可以理解 render 函数的简写方式了。

来个不同版本 vue 的区别

vue.js与vue.runtime.xxx.js的区别: vue.js是完整版的Vue,包含:核心功能+模板解析器。vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容。

修改脚手架的默认配置

使用vue inspect > output.js可以查看到Vue脚手架的默认配置。使用vue.config.js可以对脚手架进行个性化定制

脚手架中的index.html

<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><!-- 针对IE浏览器的一个特殊配置,含义是让IE浏览器以最高的渲染级别渲染页面 --><meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- 开启移动端的理想视口 --><meta name="viewport" content="width=device-width,initial-scale=1.0"><!-- 配置页签图标 --><link rel="icon" href="<%= BASE_URL %>favicon.ico"><!-- 引入第三方样式 --><link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css"><!-- 配置网页标题 --><title>硅谷系统</title></head><body><!-- 当浏览器不支持js时noscript中的元素就会被渲染 --><noscript><strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><!-- 容器 --><div id="app"></div><!-- built files will be auto injected --></body></html>

2.2 vue中的一些属性

ref属性

被用来给元素或子组件注册引用信息(id的替代者)应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)使用方式: 打标识:<h1 ref="xxx">.....</h1><School ref="xxx"></School>获取:this.$refs.xxx

具体案例

<template><div><h1 v-text="msg" ref="title"></h1><button ref="btn" @click="showDOM">点我输出上方的DOM元素</button><School ref="sch"/></div></template><script>//引入School组件import School from './components/School'export default {name:'App',components:{School},data() {return {msg:'欢迎学习Vue!'}},methods: {showDOM(){console.log(this.$refs.title) //真实DOM元素console.log(this.$refs.btn) //真实DOM元素console.log(this.$refs.sch) //School组件的实例对象(vc)}},}</script>

props配置项

功能:让组件接收外部传过来的数据

传递数据:<Demo name="xxx"/>

接收数据:

第一种方式(只接收):props:['name']

第二种方式(限制类型):props:{name:String}

第三种方式(限制类型、限制必要性、指定默认值):

props:{name:{type:String, //类型required:true, //必要性default:'老王' //默认值}}

备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

示例代码:

父组件给子组件传数据

App.vue

<template><div id="app"><img alt="Vue logo" src="./assets/logo.png"><Student></Student><School name="haha" :age="this.age"></School></div></template><script>import School from './components/School.vue'import Student from './components/Student.vue'export default {name: 'App',data () {return {age: 360 }},components: {School,Student}}</script><style>#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;}</style>

School.vue

<template><div class="demo"><h2>学校名称:{{ name }}</h2><h2>学校年龄:{{ age }}</h2><h2>学校地址:{{ address }}</h2><button @click="showName">点我提示学校名</button></div></template><script>export default {name: "School",// 最简单的写法:props: ['name', 'age']props: {name: {type: String,required: true // 必须要传的},age: {type: Number,required: true}},data() {return {address: "北京昌平",};},methods: {showName() {alert(this.name);},},};</script><style>.demo {background-color: orange;}</style>

mixin(混入)

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

例子:

// 定义一个混入对象var myMixin = {created: function () {this.hello()},methods: {hello: function () {console.log('hello from mixin!')}}}// 定义一个使用混入对象的组件var Component = Vue.extend({mixins: [myMixin]})

选项合并

当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。

比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。

var mixin = {data: function () {return {message: 'hello',foo: 'abc'}}}new Vue({mixins: [mixin],data: function () {return {message: 'goodbye',bar: 'def'}},created: function () {console.log(this.$data)// => { message: "goodbye", foo: "abc", bar: "def" }}})

同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。

var mixin = {created: function () {console.log('混入对象的钩子被调用')}}new Vue({mixins: [mixin],created: function () {console.log('组件钩子被调用')}})// => "混入对象的钩子被调用"// => "组件钩子被调用"

值为对象的选项,例如methodscomponentsdirectives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。

var mixin = {methods: {foo: function () {console.log('foo')},conflicting: function () {console.log('from mixin')}}}var vm = new Vue({mixins: [mixin],methods: {bar: function () {console.log('bar')},conflicting: function () {console.log('from self')}}})vm.foo() // => "foo"vm.bar() // => "bar"vm.conflicting() // => "from self"

全局混入不建议使用

插件

插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制。

通过全局方法Vue.use()使用插件。它需要在你调用new Vue()启动应用之前完成:

// 调用 `MyPlugin.install(Vue)`Vue.use(MyPlugin)new Vue({// ...组件选项})

本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

定义插件:

对象.install = function (Vue, options) {// 1. 添加全局过滤器Vue.filter(....)// 2. 添加全局指令Vue.directive(....)// 3. 配置全局混入(合)Vue.mixin(....)// 4. 添加实例方法Vue.prototype.$myMethod = function () {...}Vue.prototype.$myProperty = xxxx}

具体案例:

plugin.js

export default {install(Vue, x, y, z) {console.log(x, y, z)//全局过滤器Vue.filter('mySlice', function (value) {return value.slice(0, 4)})//定义全局指令Vue.directive('fbind', {//指令与元素成功绑定时(一上来)bind(element, binding) {element.value = binding.value},//指令所在元素被插入页面时inserted(element, binding) {element.focus()},//指令所在的模板被重新解析时update(element, binding) {element.value = binding.value}})//定义混入Vue.mixin({data() {return {x: 100,y: 200}},})//给Vue原型上添加一个方法(vm和vc就都能用了)Vue.prototype.hello = () => {alert('你好啊aaaa') }}}

main.js

// 引入插件import plugin from './plugin'// 使用插件Vue.use(plugin)

然后就可以在别的组件使用插件里的功能了。

scoped样式

作用:让样式在局部生效,防止冲突。写法:<style scoped>

具体案例:

<style lang="less" scoped>.demo{background-color: pink;.atguigu{font-size: 40px;}}</style>

总结TodoList案例

组件化编码流程:

​ (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。

​ (2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

​ 1).一个组件在用:放在组件自身即可。

​ 2). 一些组件在用:放在他们共同的父组件上(状态提升)。

​ (3).实现交互:从绑定事件开始。

props适用于:

​ (1).父组件 ==> 子组件 通信

​ (2).子组件 ==> 父组件 通信(要求父先给子一个函数)

使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!

props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

2.3 浏览器本地存储

Cookie

Cookie是最早被提出来的本地存储方式,在此之前,服务端是无法判断网络中的两个请求是否是同一用户发起的,为解决这个问题,Cookie就出现了。Cookie 是存储在用户浏览器中的一段不超过 4 KB 的字符串。它由一个名称(Name)、一个值(Value)和其它几个用 于控制 Cookie 有效期、安全性、使用范围的可选属性组成。不同域名下的 Cookie 各自独立,每当客户端发起请求时,会自动把当前域名下所有未过期的 Cookie 一同发送到服务器。

Cookie的特性:

Cookie一旦创建成功,名称就无法修改Cookie是无法跨域名的,也就是说a域名和b域名下的cookie是无法共享的,这也是由Cookie的隐私安全性决定的,这样就能够阻止非法获取其他网站的Cookie每个域名下Cookie的数量不能超过20个,每个Cookie的大小不能超过4kb有安全问题,如果Cookie被拦截了,那就可获得session的所有信息,即使加密也于事无补,无需知道cookie的意义,只要转发cookie就能达到目的Cookie在请求一个新的页面的时候都会被发送过去

Cookie 在身份认证中的作用

客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的 Cookie,客户端会自动 将 Cookie 保存在浏览器中。

随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的 Cookie,通过请求头的形式发送给 服务器,服务器即可验明客户端的身份。

Cookie 不具有安全性

由于 Cookie 是存储在浏览器中的,而且浏览器也提供了读写 Cookie 的 API,因此 Cookie 很容易被伪造,不具有安全 性。因此不建议服务器将重要的隐私数据,通过 Cookie 的形式发送给浏览器。

注意:千万不要使用 Cookie 存储重要且隐私的数据!比如用户的身份信息、密码等。

Session

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了session是一种特殊的cookie。cookie是保存在客户端的,而session是保存在服务端。

为什么要用session

由于cookie 是存在用户端,而且它本身存储的尺寸大小也有限,最关键是用户可以是可见的,并可以随意的修改,很不安全。那如何又要安全,又可以方便的全局读取信息呢?于是,这个时候,一种新的存储会话机制:session 诞生了

session原理

当客户端第一次请求服务器的时候,服务器生成一份session保存在服务端,将该数据(session)的id以cookie的形式传递给客户端;以后的每次请求,浏览器都会自动的携带cookie来访问服务器(session数据id)。

图示:

session我觉得可以简单理解为一个表,根据cookie传来的值查询表中的内容

session 标准工作流程

我在 node.js 中详细演示了一遍 session 的使用,具体看了另一篇博客:/hangao233/article/details/123089029

LocalStorage

LocalStorage是HTML5新引入的特性,由于有的时候我们存储的信息较大,Cookie就不能满足我们的需求,这时候LocalStorage就派上用场了。

LocalStorage的优点:

在大小方面,LocalStorage的大小一般为5MB,可以储存更多的信息LocalStorage是持久储存,并不会随着页面的关闭而消失,除非主动清理,不然会永久存在仅储存在本地,不像Cookie那样每次HTTP请求都会被携带

LocalStorage的缺点:

存在浏览器兼容问题,IE8以下版本的浏览器不支持如果浏览器设置为隐私模式,那我们将无法读取到LocalStorageLocalStorage受到同源策略的限制,即端口、协议、主机地址有任何一个不相同,都不会访问

LocalStorage的常用API:

// 保存数据到 localStoragelocalStorage.setItem('key', 'value');// 从 localStorage 获取数据let data = localStorage.getItem('key');// 从 localStorage 删除保存的数据localStorage.removeItem('key');// 从 localStorage 删除所有保存的数据localStorage.clear();// 获取某个索引的KeylocalStorage.key(index)

LocalStorage的使用场景:

有些网站有换肤的功能,这时候就可以将换肤的信息存储在本地的LocalStorage中,当需要换肤的时候,直接操作LocalStorage即可在网站中的用户浏览信息也会存储在LocalStorage中,还有网站的一些不常变动的个人信息等也可以存储在本地的LocalStorage中

SessionStorage

SessionStorage和LocalStorage都是在HTML5才提出来的存储方案,SessionStorage 主要用于临时保存同一窗口(或标签页)的数据,刷新页面时不会删除,关闭窗口或标签页之后将会删除这些数据。

SessionStorage与LocalStorage对比:

SessionStorage和LocalStorage都在本地进行数据存储;SessionStorage也有同源策略的限制,但是SessionStorage有一条更加严格的限制,SessionStorage只有在同一浏览器的同一窗口下才能够共享;LocalStorage和SessionStorage都不能被爬虫爬取

SessionStorage的常用API:

// 保存数据到 sessionStoragesessionStorage.setItem('key', 'value');// 从 sessionStorage 获取数据let data = sessionStorage.getItem('key');// 从 sessionStorage 删除保存的数据sessionStorage.removeItem('key');// 从 sessionStorage 删除所有保存的数据sessionStorage.clear();// 获取某个索引的KeysessionStorage.key(index)

SessionStorage的使用场景

由于SessionStorage具有时效性,所以可以用来存储一些网站的游客登录的信息,还有临时的浏览记录的信息。当关闭网站之后,这些信息也就随之消除了。

具体案例:

localStorage

<!DOCTYPE html><html><head><meta charset="UTF-8" /><title>localStorage</title></head><body><h2>localStorage</h2><button onclick="saveData()">点我保存一个数据</button><button onclick="readData()">点我读取一个数据</button><button onclick="deleteData()">点我删除一个数据</button><button onclick="deleteAllData()">点我清空一个数据</button><script type="text/javascript" >let p = {name:'张三',age:18}function saveData(){localStorage.setItem('msg','hello!!!')localStorage.setItem('msg2',666)// 转成 JSON 对象存进去localStorage.setItem('person',JSON.stringify(p))}function readData(){console.log(localStorage.getItem('msg'))console.log(localStorage.getItem('msg2'))const result = localStorage.getItem('person')console.log(JSON.parse(result))// console.log(localStorage.getItem('msg3'))}function deleteData(){localStorage.removeItem('msg2')}function deleteAllData(){localStorage.clear()}</script></body></html>

sessionStorage

<!DOCTYPE html><html><head><meta charset="UTF-8" /><title>sessionStorage</title></head><body><h2>sessionStorage</h2><button onclick="saveData()">点我保存一个数据</button><button onclick="readData()">点我读取一个数据</button><button onclick="deleteData()">点我删除一个数据</button><button onclick="deleteAllData()">点我清空一个数据</button><script type="text/javascript" >let p = {name:'张三',age:18}function saveData(){sessionStorage.setItem('msg','hello!!!')sessionStorage.setItem('msg2',666)// 转换成JSON 字符串存进去sessionStorage.setItem('person',JSON.stringify(p))}function readData(){console.log(sessionStorage.getItem('msg'))console.log(sessionStorage.getItem('msg2'))const result = sessionStorage.getItem('person')console.log(JSON.parse(result))// console.log(sessionStorage.getItem('msg3'))}function deleteData(){sessionStorage.removeItem('msg2')}function deleteAllData(){sessionStorage.clear()}</script></body></html>

2.4 组件自定义事件

组件自定义事件是一种组件间通信的方式,适用于:子组件 ===> 父组件

使用场景

A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

绑定自定义事件:

第一种方式,在父组件中:<Demo @atguigu="test"/><Demo v-on:atguigu="test"/>

具体代码

App.vue

<template><div class="app"><!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) --><Student @atguigu="getStudentName"/> </div></template><script>import Student from './components/Student'export default {name:'App',components:{Student},data() {return {msg:'你好啊!',studentName:''}},methods: {getStudentName(name,...params){console.log('App收到了学生名:',name,params)this.studentName = name}}}</script><style scoped>.app{background-color: gray;padding: 5px;}</style>

Student.vue

<template><div class="student"><button @click="sendStudentlName">把学生名给App</button></div></template><script>export default {name:'Student',data() {return {name:'张三',}},methods: {sendStudentlName(){//触发Student组件实例身上的atguigu事件this.$emit('atguigu',this.name,666,888,900)}},}</script><style lang="less" scoped>.student{background-color: pink;padding: 5px;margin-top: 30px;}</style>

第二种方式,在父组件中:

使用this.$refs.xxx.$on()这样写起来更灵活,比如可以加定时器啥的。

具体代码

App.vue

<template><div class="app"><!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) --><Student ref="student"/></div></template><script>import Student from './components/Student'export default {name:'App',components:{Student},data() {return {studentName:''}},methods: {getStudentName(name,...params){console.log('App收到了学生名:',name,params)this.studentName = name},},mounted() {this.$refs.student.$on('atguigu',this.getStudentName) //绑定自定义事件// this.$refs.student.$once('atguigu',this.getStudentName) //绑定自定义事件(一次性)},}</script><style scoped>.app{background-color: gray;padding: 5px;}</style>

Student.vue

<template><div class="student"><button @click="sendStudentlName">把学生名给App</button></div></template><script>export default {name:'Student',data() {return {name:'张三',}},methods: {sendStudentlName(){//触发Student组件实例身上的atguigu事件this.$emit('atguigu',this.name,666,888,900)}},}</script><style lang="less" scoped>.student{background-color: pink;padding: 5px;margin-top: 30px;}</style>

若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

触发自定义事件:this.$emit('atguigu',数据)

使用 this.$emit() 就可以子组件向父组件传数据

解绑自定义事件this.$off('atguigu')

代码

this.$off('atguigu') //解绑一个自定义事件// this.$off(['atguigu','demo']) //解绑多个自定义事件// this.$off() //解绑所有的自定义事件

组件上也可以绑定原生DOM事件,需要使用native修饰符。

代码

<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) --><Student ref="student" @click.native="show"/>

注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

2.5 全局事件总线

一种组件间通信的方式,适用于任意组件间通信。

安装全局事件总线:

new Vue({......beforeCreate() {Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm},......})

使用事件总线:

接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。

methods(){demo(data){......}}......mounted() {this.$bus.$on('xxxx',this.demo)}

提供数据:this.$bus.$emit('xxxx',数据)

最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

示例代码

School.vue

<template><div class="school"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2></div></template><script>export default {name:'School',data() {return {name:'尚硅谷',address:'北京',}},methods: {demo(data) {console.log('我是School组件,收到了数据',data)}}mounted() {// console.log('School',this)this.$bus.$on('hello',this.demo)},beforeDestroy() {this.$bus.$off('hello')},}</script><style scoped>.school{background-color: skyblue;padding: 5px;}</style>

Student.vue

<template><div class="student"><h2>学生姓名:{{name}}</h2><h2>学生性别:{{sex}}</h2><button @click="sendStudentName">把学生名给School组件</button></div></template><script>export default {name:'Student',data() {return {name:'张三',sex:'男',}},mounted() {// console.log('Student',this.x)},methods: {sendStudentName(){this.$bus.$emit('hello',this.name)}},}</script><style lang="less" scoped>.student{background-color: pink;padding: 5px;margin-top: 30px;}</style>

2.6 消息订阅与发布

一种组件间通信的方式,适用于任意组件间通信。

使用步骤:

安装pubsub:npm i pubsub-js

引入:import pubsub from 'pubsub-js'

接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。

methods:{demo(data){......}}......mounted() {this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息}

提供数据:pubsub.publish('xxx',数据)

最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)去取消订阅。

示例代码

订阅消息

School.vue

<template><div class="school"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2></div></template><script>import pubsub from 'pubsub-js'export default {name:'School',data() {return {name:'尚硅谷',address:'北京',}},mounted() {// console.log('School',this)/* this.$bus.$on('hello',(data)=>{console.log('我是School组件,收到了数据',data)}) */this.pubId = pubsub.subscribe('hello',(msgName,data)=>{console.log(this)// console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)})},beforeDestroy() {// this.$bus.$off('hello')pubsub.unsubscribe(this.pubId)},}</script><style scoped>.school{background-color: skyblue;padding: 5px;}</style>

发布消息

Student.vue

<template><div class="student"><h2>学生姓名:{{name}}</h2><h2>学生性别:{{sex}}</h2><button @click="sendStudentName">把学生名给School组件</button></div></template><script>import pubsub from 'pubsub-js'export default {name:'Student',data() {return {name:'张三',sex:'男',}},mounted() {// console.log('Student',this.x)},methods: {sendStudentName(){// this.$bus.$emit('hello',this.name)pubsub.publish('hello',666)}},}</script><style lang="less" scoped>.student{background-color: pink;padding: 5px;margin-top: 30px;}</style>

2.7 nextTick

语法:this.$nextTick(回调函数)作用:在下一次 DOM 更新结束后执行其指定的回调。什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。

具体案例

this.$nextTick(function(){this.$refs.inputTitle.focus()}

2.8 Vue封装的过度与动画

作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。

图示:

写法:

准备好样式:

元素进入的样式: v-enter:进入的起点v-enter-active:进入过程中v-enter-to:进入的终点 元素离开的样式: v-leave:离开的起点v-leave-active:离开过程中v-leave-to:离开的终点

使用<transition>包裹要过渡的元素,并配置name属性:

<transition name="hello"><h1 v-show="isShow">你好啊!</h1></transition>

备注:若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值。

具体案例(单个元素过渡)

<template><div><button @click="isShow = !isShow">显示/隐藏</button><transition appear><h1 v-show="isShow">你好啊!</h1></transition></div></template><script>export default {name:'Test',data() {return {isShow:true}},}</script><style scoped>h1{background-color: orange;}.v-enter-active{animation: move 0.5s linear;}.v-leave-active{animation: move 0.5s linear reverse;}@keyframes move {from{transform: translateX(-100%);}to{transform: translateX(0px);}}</style>

name 的作用可以让让不同的元素有不同的动画效果

<template><div><button @click="isShow = !isShow">显示/隐藏</button><transition name="hello" appear><h1 v-show="isShow">你好啊!</h1></transition></div></template><script>export default {name:'Test',data() {return {isShow:true}},}</script><style scoped>h1{background-color: orange;}.hello-enter-active{animation: move 0.5s linear;}.hello-leave-active{animation: move 0.5s linear reverse;}@keyframes move {from{transform: translateX(-100%);}to{transform: translateX(0px);}}</style>

具体案例(多个元素过渡)

<template><div><button @click="isShow = !isShow">显示/隐藏</button><transition-group name="hello" appear><h1 v-show="!isShow" key="1">你好啊!</h1><h1 v-show="isShow" key="2">尚硅谷!</h1></transition-group></div></template><script>export default {name:'Test',data() {return {isShow:true}},}</script><style scoped>h1{background-color: orange;}/* 进入的起点、离开的终点 */.hello-enter,.hello-leave-to{transform: translateX(-100%);}.hello-enter-active,.hello-leave-active{transition: 0.5s linear;}/* 进入的终点、离开的起点 */.hello-enter-to,.hello-leave{transform: translateX(0);}</style>

使用第三库的具体案例(随便看看,这个不重要)

库的名称:Animate.css

安装:npm i animate.css

引入:import ‘animate.css’

<template><div><button @click="isShow = !isShow">显示/隐藏</button><transition-group appearname="animate__animated animate__bounce" enter-active-class="animate__swing"leave-active-class="animate__backOutUp"><h1 v-show="!isShow" key="1">你好啊!</h1><h1 v-show="isShow" key="2">尚硅谷!</h1></transition-group></div></template><script>import 'animate.css'export default {name:'Test',data() {return {isShow:true}},}</script><style scoped>h1{background-color: orange;}</style>

2.9 vue脚手架配置代理

可以用来解决跨域的问题

ajax 是前端技术,你得有浏览器,才有window对象,才有xhr,才能发ajax请求,服务器之间通信就用传统的http请求就行了。

方法一

​ 在vue.config.js中添加如下配置:

devServer:{proxy:"http://localhost:5000"}

说明:

优点:配置简单,请求资源时直接发给前端(8080)即可。缺点:不能配置多个代理,不能灵活的控制请求是否走代理。工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

方法二

​ 编写vue.config.js配置具体代理规则:

module.exports = {devServer: {proxy: {'/api1': {// 匹配所有以 '/api1'开头的请求路径target: 'http://localhost:5000',// 代理目标的基础路径changeOrigin: true,pathRewrite: {'^/api1': ''}//代理服务器将请求地址转给真实服务器时会将 /api1 去掉},'/api2': {// 匹配所有以 '/api2'开头的请求路径target: 'http://localhost:5001',// 代理目标的基础路径changeOrigin: true,pathRewrite: {'^/api2': ''}}}}}/*changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080changeOrigin默认值为true*/

说明:

优点:可以配置多个代理,且可以灵活的控制请求是否走代理。缺点:配置略微繁琐,请求资源时必须加前缀。

2.10 slot插槽

作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件 ===> 子组件

分类:默认插槽、具名插槽、作用域插槽

使用方式:

默认插槽:

父组件中:<Category><div>html结构1</div></Category>子组件中:<template><div><!-- 定义插槽 --><slot>插槽默认内容...</slot></div></template>

具名插槽:

父组件中:<Category><template slot="center"><div>html结构1</div></template><template v-slot:footer><div>html结构2</div></template></Category>子组件中:<template><div><!-- 定义插槽 --><slot name="center">插槽默认内容...</slot><slot name="footer">插槽默认内容...</slot></div></template>

作用域插槽:

理解:数据在组件的自身(子组件),但根据数据生成的结构需要组件的使用者(父组件)来决定。(games数据在Category(子)组件中,但使用数据所遍历出来的结构由App(父)组件决定)

具体编码:

父组件中:<Category><template scope="scopeData"><!-- 生成的是ul列表 --><ul><li v-for="g in scopeData.games" :key="g">{{g}}</li></ul></template></Category><Category><template slot-scope="scopeData"><!-- 生成的是h4标题 --><h4 v-for="g in scopeData.games" :key="g">{{g}}</h4></template></Category>子组件中:<template><div><!-- 通过数据绑定就可以把子组件的数据传到父组件 --><slot :games="games"></slot></div></template><script>export default {name:'Category',props:['title'],//数据在子组件自身data() {return {games:['红色警戒','穿越火线','劲舞团','超级玛丽']}},}</script>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。