Vue进阶脚手架开发
1、分析脚手架
├── 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:包版本控制文件
2、render函数
//main.js
import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = falsenew Vue({el:"#app",render(createElement){return createElement('h1',"你好啊")}
})
render是函数,能创建元素,再精简点
render: createElement=>createElement('h1',"你好啊")
new Vue({el:"#app",render:h=>h(App)})
关于不同版本的Vue:
1.vue.js与vue.runtime.xxx.js的区别:
(1).vue.js是完整版的Vue,包含:核心功能+模板解析器。
(2).vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。
2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement
函数去指定具体内容。
3、默认配置
Vue 脚手架隐藏了所有 webpack 相关的配置,若想查看具体的 webpakc 配置,
终端输入vue inspect > output.js
使用vue.config.js可以对脚手架进行个性化定制,详情见官网
module.exports = {pages: {index: {//入口entry: 'src/main.js',},},lintOnSave:false//关闭语法检查}
4、ref属性
1.获取原生dom元素原生里用id
来操作,vue里面用ref
,被用来给元素或子组件注册引用信息(id的替代者)
2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3. 使用方式:
- 打标识:
<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">点我</button><School></School><Student></Student></div>
</template><script>//引入组件import School from './components/School'import Student from './components/Student'export default {name:'App',data(){return{msg:"2021/9/14"}},components:{School,Student},methods:{showDOM:function(){console.log(this.$refs.title);console.log(this.$refs.btn);}}}
</script>
5、props配置
- 功能:让组件接收外部传过来的数据
- 传递数据:
<Demo name="xxx"/>
- 接收数据:
- 第一种方式(简单声明接收):
props:['name','age','sex']
- 第二种方式(限制数据类型):
- 第一种方式(简单声明接收):
props:{name:String,age:Number,sex:String}
- 第三种方式(限制类型、限制必要性、指定默认值):
props:{name:{type:String, //类型required:true, //必要性default:'老王' //默认值}}
示例
//app.vue
<template><div><Student name="李四" sex="女" :age="18+1"></Student></div>
</template><script>//引入组件import Student from './components/Student'export default {name:'App',components:{Student}}
</script>
//student.vue
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{age}}</h2></div>
</template><script>export default {name:'Student',props:['name','age','sex']}
</script>
动态绑定,计算双引号里面的值
<Student name="李四" sex="女" :age="18+1"></Student>
<Student name="李四" sex="女" age="18+1"></Student>
如果组件中也定义了相同名称的数据
<script>export default {name:'Student',data(){return{age:12}},props:{name:String,age:Number,sex:String}}
</script>
备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告。
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{age}}</h2><button @click="showAge">点我</button></div>
</template><script>export default {name:'Student',methods:{showAge:function(){this.age++}},//props:['name','age','sex'],//简单接收props:{name:String,age:Number,sex:String}}
</script>
若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{thisAge}}</h2><button @click="showAge">点我</button></div>
</template><script>export default {name:'Student',data(){return{thisAge:this.age}},methods:{showAge:function(){this.thisAge++}},//props:['name','age','sex'],//简单接收props:{name:String,age:Number,sex:String}}
</script>
Cate.vue
<template><div class="cate"><h3>title</h3><ul><li v-for="item in listData">{{item}}</li></ul></div>
</template><script>
export default {name:"Cate",
props:["listData","title"]
}
</script><style>
.cate{background-color:skyblue;width: 200px;height: 300px;
}
h3{text-align: center;
}</style>
//App.vue
<template><div class="container"><Cate :listData="foods" title="foods"/><Cate :listData="games" title="games"/><Cate :listData="films" title="films"/></div>
</template><script>
import Cate from './components/Cate'
export default {name:'App',
components:{Cate
},
data(){return{foods:["火锅","烧烤","炸鸡","泡面"],games:["超级玛丽","奥比岛","洛克王国","摩尔庄园"],films:["教父","峰暴","一天","巧克力工厂"],}
}
}
</script><style>
.container{display: flex;justify-content: space-around;
}
</style>
6、mixin混入
多个组件共享一个配置
- 功能:可以把
多个组件共用的配置
提取成一个混入对象 - 使用方式:
第一步定义混合:
{data(){....},methods:{....}....}
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{sex}}</h2><button @click="showName">点我</button></div>
</template><script>import {mixin}from'../mixin.js'export default {name:'Student',data(){return{name:"张三",sex:"男"}},mixins:[mixin]}
</script>
//minin.js
export const mixin={methods:{showName:function(){console.log(this.name)}
}}
第二步使用混入:
全局混入:Vue.mixin(xxx)
在main.js中写入
局部混入:mixins:['xxx']
在组件中写
7、插件
- 功能:用于增强Vue
- 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
- 定义插件:
//plugins.js对象.install = function (Vue, options) {// 1. 添加全局过滤器Vue.filter(....)// 2. 添加全局指令Vue.directive(....)// 3. 配置全局混入(合)Vue.mixin(....)// 4. 添加实例方法Vue.prototype.$myMethod = function () {...}Vue.prototype.$myProperty = xxxx}
- 使用插件:
Vue.use()
//main.js//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import plugins from './plugins'
//关闭Vue的生产提示
Vue.config.productionTip = false//应用(使用)插件
Vue.use(plugins,1,2,3)
//创建vm
new Vue({el:'#app',render: h => h(App)
})
8、scoped样式
- 作用:让样式在局部生效,防止冲突。
- 写法:
<style scoped>
- 写在App.vue不太适用
安装less-loader
npm i less-loader@7.2.3
查看插件版本
npm view less-loader versions
<style lang="less" scoped>.demo{background-color: pink;.atguigu{font-size: 40px;}}
</style>
9、浏览器缓存
- 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
- 浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。
- 相关API:
xxxxxStorage.setItem('key', 'value');
该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
JSON.stringify
将 JavaScript 值转换为 JSON 字符串
JSON.parse
将数据转换为 JavaScript 对象
xxxxxStorage.getItem('person');
该方法接受一个键名作为参数,返回键名对应的值。
xxxxxStorage.removeItem('key');
该方法接受一个键名作为参数,并把该键名从存储中删除。
xxxxxStorage.clear()
该方法会清空存储中的所有数据。 - 备注:
- SessionStorage存储的内容会随着浏览器窗口关闭而消失。
- LocalStorage存储的内容,需要手动清除才会消失。
xxxxxStorage.getItem(xxx)
如果xxx对应的value获取不到,那么getItem的返回值是null。JSON.parse(null)
的结果依然是null。
10、组件自定义事件
通过父组件给子组件传递函数类型的props实现:子给父传递数据
//School.vue
<template><div><h2>学校:{{name}}</h2><h2>地址:{{address}}</h2><button @click="sendSchoolName">点我</button></div>
</template><script>export default {name:'School',data(){return{name:"一中",address:"广州"}},props:['getSchoolName'],methods: {sendSchoolName(){//传递过来了以后要调用this.getSchoolName(this.name)}},}
</script>
//App.vue
<template><div><Student></Student><hr>//通过父组件给子组件传递函数类型的props实现:子给父传递数据<School :getSchoolName="getSchoolName"></School></div>
</template><script>//引入组件
import Student from './components/Student.vue'
import School from './components/School.vue'export default {name:'App',components:{Student,School},methods:{getSchoolName:function(name){console.log("App收到了name",name);},}}
</script>
通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on)
//App.vue
<template><div><Student @dianji="getStudentName"/>//父组件给子组件绑定一个自定义事件实现</div>
</template><script>//引入组件
import Student from './components/Student.vue'export default {name:'App',components:{Student,},methods:{getStudentName(name,...params){console.log('App收到了学生名:',name,params)this.studentName = name},}}
</script>
//Student.vue
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{sex}}</h2><button @click="sendStudentlName">点我</button></div>
</template><script>import {mixin}from'../mixin.js'export default {name:'Student',data(){return{name:"张三",sex:"男"}},methods:{sendStudentlName(){//需要绑定点击触发//触发Student组件实例身上的dianji事件//子给父传递数据this.$emit('dianji',this.name,666,888,900)},}}
</script>
通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref
//App.vue
<template><div><Student ref="student"/></div>
</template><script>//引入组件
import Student from './components/Student.vue'
import School from './components/School.vue'export default {name:'App',components:{Student,School},methods:{getStudentName(name,...params){console.log('App收到了学生名:',name,params)this.studentName = name},},mounted() {//给student标签绑定一个点击事件,然后这个事件会调用方法this.$refs.student.$on('dianji',this.getStudentName) //绑定自定义事件// this.$refs.student.$once('atguigu',this.getStudentName) //绑定自定义事(一次性)},}
</script>
//Student.vue
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{sex}}</h2><button @click="sendStudentlName">点我</button></div>
</template><script>import {mixin}from'../mixin.js'export default {name:'Student',data(){return{name:"张三",sex:"男"}},methods:{sendStudentlName(){//触发Student组件实例身上的dianji事件this.$emit('dianji',this.name,666,888,900)},}}
</script>
一个是通过vue的@绑定自定义事件,一个是通过ref属性获取到dom元素然后绑定自定义事件
- 若想让自定义事件只能触发一次,可以使用
once
修饰符,或$once
方法。 - 触发自定义事件:
this.$emit('dianji',数据)
- 解绑自定义事件
this.$off('dianji')
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{sex}}</h2><button @click="sendStudentlName">点我输出</button><button @click="unbind">点我解绑</button></div>
</template>
<script>export default {name:'Student',data(){return{name:"张三",sex:"男"}},methods:{sendStudentlName(){//触发Student组件实例身上的dianji事件this.$emit('dianji',this.name,666,888,900)},unbind(){this.$off("dianji")//解绑一个事件this.$off(["dianji","demo"])//解绑多个事件this.$off()//解绑所有事件}},}
</script>
如果调用this.destory,那么所有自定义属性都会被解绑,因为绑定的实例对象已经被销毁了
4. 组件上也可以绑定原生DOM事件,需要使用native
修饰符,不然会默认认为绑定的是自定义事件。
<Student ref="student" @click.native="方法名"></Student>
- 注意:通过
this.$refs.xxx.$on('dianji',回调函数)
绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
11、全局事件总线
- 一种组件间通信的方式,适用于任意组件间通信。
- 安装全局事件总线:
//App.vuenew Vue({......beforeCreate() {//this指向这个vue实例对象Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm},......})
- 使用事件总线:
- 接收数据:A组件想接收数据,则在A组件中给
$bus
绑定自定义事件,事件的回调留在A组件自身。
- 接收数据:A组件想接收数据,则在A组件中给
methods(){demo(data){......}}......mounted() {this.$bus.$on('xxxx',this.demo)}
- 提供数据:
this.$bus.$emit('xxxx',数据)
- 最好在
beforeDestroy
钩子中,用$off
去解绑当前组件所用到的事件。
实现Student、School组件间的相互通信,Student组件传递信息给School组件,School组件绑定自定义方法,然后Student组件emit触发,并且传递参数进行通信,
//main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
//创建vm
new Vue({el:'#app',render: h => h(App),beforeCreate() {Vue.prototype.$bus = this //安装全局事件总线},
})
//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>
//School.vue
<template><div class="school"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2></div>
</template>
<script>export default {name:'School',data() {return {name:'二中',address:'北京',}},mounted() {// console.log('School',this)this.$bus.$on('hello',(data)=>{console.log('我是School组件,收到了数据',data)})},beforeDestroy() {this.$bus.$off('hello')},}
</script>
12、消息的订阅和发布
- 一种组件间通信的方式,适用于任意组件间通信。
- 使用步骤:
- 安装pubsub:
npm i pubsub-js
- 引入:
import pubsub from 'pubsub-js'
- 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
- 提供数据:
pubsub.publish('xxx',数据)
- 最好在beforeDestroy钩子中,用
PubSub.unsubscribe(pid)
去取消订阅。
- 安装pubsub:
School组件订阅然后Student组件发布信息实现组件间的通信
语法:
(1) import PubSub from ‘pubsub-js’ // 引入
(2) PubSub.subscribe(‘msgName’, functon(msgName, data){ })
(3) PubSub.publish(‘msgName’, data): 发布消息, 触发订阅的回调函数调用
(4) PubSub.unsubscribe(token): 取消消息的订阅
//School.vue
<template><div><h2>学校:{{name}}</h2><h2>地址:{{address}}</h2></div>
</template><script>
import pubsub from 'pubsub-js'export default {name:'School',data(){return{name:"一中",address:"广州"}},mounted(){this.pubId =pubsub.subscribe('hello',(a,b)=>{console.log("11111111111",a,b)})},beforeDestroy() {pubsub.unsubscribe(this.pubId)//取消订阅},}
</script>
//Student.vue
<template><div><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(){},methods:{sendStudentName(){pubsub.publish('hello',this.name)}}}
</script>
13、this.$nextTick
- 语法:
this.$nextTick
(回调函数) - 作用:在下一次 DOM 更新结束后执行其指定的回调。
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
<template><button ref="tar" type="button" name="button" @click="testClick">{{content}}</button>
</template><script>export default {data () {return {content: '初始值'}}methods: {testClick(){this.content = '改变了的值'// 这时候直接打印的话,由于dom元素还没更新// 因此打印出来的还是未改变之前的值console.log(this.$refs.tar.innerText) // 初始值}}}
</script>
this.$nextTick
这个方法作用是当数据被修改后使用这个方法会回调获取更新后的dom再渲染出来
methods:{testClick() {this.content = '改变了的值'let that = thisthis.$nextTick(() => {// dom元素更新后执行,因此这里能正确打印更改之后的值console.log(that.$refs.tar.innerText) // 改变了的值})}
}
14、插槽
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件 ===> 子组件
14.1、默认插槽
如果组件标签里没有插入内容的时候,不会显示
如果有插入内容,会显示
父组件中:
//App.vue<Category><div>html结构1</div></Category>
当使用的组件标签中插入内容时,插入的内容会被放到组件的slot标签中
子组件中:
//Category.vue
<template><div><!-- 定义插槽 --><slot>我是默认内容</slot></div>
</template>
像下面组件标签中加入了图片标签
//App.vue
<template><div class="container"><Category :listData="foods" title="foods"><img src="https://z3.ax1x.com/2021/09/25/4rtPMV.png" alt=""></Category></div>
</template>
如果组件标签内没有没有放标签
//App.vue
<template><div class="container"><Category :listData="foods" title="foods"></Category></div>
</template>
组件标签中没有插入其他标签
14.2、具名插槽
具名插槽则是当子组件需要显示不同的效果时使用具名插槽,通过name属性给插槽命名。
父组件中:
写法一:
//App.vue<Category><template slot="center"><div>html结构1</div></template></Category>
写法二:
//App.vue<Category><template v-slot:footer><div>html结构2</div></template></Category>
子组件中:
//Category.vue<template><div><!-- 定义插槽 --><slot name="center">插槽默认内容...</slot><slot name="footer">插槽默认内容...</slot></div></template>
具体代码
//Cate.vue
<template><div class="cate"><h3>title</h3><slot name="center">我是默认值1111</slot><slot name="footer">我是默认值2222</slot></div>
</template><script>
export default {name:"Cate",
props:["listData","title"]
}
</script><style>
.cate{background-color:skyblue;width: 200px;height: 300px;
}
h3{text-align: center;
}</style>
//App.vue
<template><div class="container"><Cate title="foods"><img slot="center" src="https://z3.ax1x.com/2021/09/25/4rtPMV.png" alt=""><template v-slot:footer><h4>更多图片</h4></template></Cate></div>
</template><script>
import Cate from './components/Cate'
export default {name:'App',
components:{Cate
},
data(){return{foods:["火锅","烧烤","炸鸡","泡面"],games:["超级玛丽","奥比岛","洛克王国","摩尔庄园"],films:["教父","峰暴","一天","巧克力工厂"],}
}
}
</script><style>
.container{display: flex;justify-content: space-around;
}
img{width: 100%;
}
</style>>
14.3、作用域插槽
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
需要组件的使用者收到了数据,怎么使用取决于组件的使用者
(games数据在Cate组件中,但使用数据所遍历出来的结构由App组件决定)
作用域插槽语法,必须要使用template
<template scope="scopeData">{{scopeData}}</template>
//App.vue
<template><div class="container"><Cate><template scope="scopeData">{{scopeData}}</template></Cate></div>
</template><script>
import Cate from './components/Cate'
export default {name:'App',
components:{Cate
}
}
</script>
//Cate.vue
<template><div class="cate"><h3>{{title}}</h3><slot :games="games">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
</div>
</template><script>
export default {name:"Cate",
props:["title"],
data(){return{games:["超级玛丽","奥比岛","洛克王国","摩尔庄园"],}
}
}
</script>
<template scope="scopeData">{{scopeData}}</template>
这个收到是一个对象,就是下面图所示,我们需要的是.games
<template scope="scopeData">{{scopeData.games}}</template>
Vue进阶脚手架开发相关推荐
- Vue进阶(五十三):vue-cli 脚手架 webpack.prod.conf.js 配置文件详解
文章目录 一.前言 二.optimize-css-assets-webpack-plugin 插件 三.拓展阅读 一.前言 webpack.prod.conf.js 配置文件是webpack生产环境核 ...
- Vue教程03-Vue脚手架开发环境
Vue脚手架开发环境 1.Vue开发环境的安装 1.1安装Node JS 1.2全局安装Vue脚手架 1.3安装HBuilderX 1.4强烈推荐安装以下工具软件 2.HBuilderX创建Vue项目 ...
- ehcache springboot_阿里内部进阶学习SpringBoot+Vue全栈开发实战文档
前言 Spring 作为一个轻量级的容器,在JavaEE开发中得到了广泛的应用,但是Spring 的配置烦琐臃肿,在和各种第三方框架进行整合时代码量都非常大,并且整合的代码大多是重复的,为了使开发者能 ...
- Vue项目构建开发入门
Vue项目构建开发入门 开篇:Vue CLI 3 项目构建基础 大家好,当你点进这个标题,开始阅读本章的时候,说明你对 Vue.js 是充满好奇心和求知欲的.我之前写过一篇文章,这样评价 Vue.js ...
- Vue进阶——Vue CLI
Vue进阶--Vue CLI 前言 一.什么是Vue CLI? 二.怎么安装Vue CLI? 1.Node 版本要求 2.已安装旧版本 3.安装完成 三.Vue CLI 基础运用 1.Vue ui项目 ...
- Vue进阶(二):Vue 项目文件结构介绍
文章目录 一.文件介绍 二.Vue 加载 main.js 过程分析 三.注 四.拓展阅读 一.文件介绍 main.js是项目主入口文件,主要作用是初始化vue实例,并引入所需插件: App.vue是项 ...
- vue.cli脚手架初次使用图文教程
vue-cli作用 vue-cli作为vue的脚手架,可以帮助我们在实际开发中自动生成vue.js的模板工程. vue-cli使用 !!前提:需要vue和webpack 安装全局vue-cli npm ...
- VUE学习和开发中的注意点总结(一),便于回顾(不断完善补充。)
1.export 和export default 的区别? 在JavaScript ES6中,export与export default均可用于导出常量.函数.文件.模块等,你可以在其它文件或模块中通 ...
- Vue 基础的开发环境
本期节目将手把手教你去 NPM 市场买最新鲜的食材,只为搭配 小鲜肉 Vue 下厨. 既然它是当红小鲜肉,我想有必要写一篇文章来帮助大家配置好 Vue 的生产环境,我给它的总体评价是"简单却 ...
最新文章
- 生物信息行业应该具备哪些基础素养?重点应该放在计算机方面还是生物方面或者说其他?
- call_user_func
- 山西五台警方通报“男子强拽女学生”:嫌疑人被刑拘
- js获取浏览器活跃页面,切换tab页状态
- Android学习笔记(一)
- Flask使用Flask-SQLAlchemy操作MySQL数据库
- [转载] java8 lambda表达式 List转为Map
- Maven的下载与安装
- 微服务(接口)设计原则
- 还有在用迅雷7的朋友吗?
- 移动通信(Mobile Communication)
- 用Python实现双色球随机选号
- Word批量打印软件/工具
- 音频amr格式怎么转成mp3-几个步骤轻松搞定
- 推荐10款最好的免费项目管理工具
- usb计算机连接 不再弹出,电脑usb无法安全弹出问题解决办法
- 【渝粤教育】电大中专电商运营实操 (4)作业 题库
- python图像切割成多边形_python opencv在图像中裁剪任意形状多边形,裁剪镂空多边形, 裁剪多个多边形...
- 2022中国眼博会,中国北京国际儿童青少年眼睛健康产业展览会
- 汽车租赁APP应用开发