Vue之webpack
1.webpack概念
前端规范:模块化、组件化、自动化、规范化
为了实现前端项目工程化,webpack诞生,webpack是一种前端工程化的解决方案。
npm install webpack@5.42.1 webpack-cli@4.7.2 -D
webpack的手写过程就先看一遍,后面深入研究
2.Vue
Vue是一套用于构建用户界面的前端框架
两个特点:
1.数据驱动视图,数据一旦变化,视图就变化(页面会重新渲染)。数据驱动视图是单向的
2.数据双向绑定,页面一旦变化,数据也变化。
一个最简单的例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 导入vue.js就把vue变成了全局变量 -->
<script src="./lib/vue.js"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
</body>
</html>
3.Vue指令
1.内容渲染指令
内容渲染指令用来渲染DOM元素中的文本内容。常用的内容渲染指令:
- v-text
- {{}}
- v-html
1.v-text:会覆盖标签内原本的内容(缺点)
<p v-text="name">姓名</p>
data: {
name: 'zhangsan'
}
// 结果是zhangsan,覆盖了里面原本的姓名
2.{{}};插值字符串,不会覆盖原来的内容
<div id="app">
大家好,{{ message }}
</div>
data: {
message: 'Hello Vue!'
}
3.v-html:会解析里面的html代码
<p v-html="text"></p>
data: {
text: '<span style="color:red;">zhangsan</span>'
}
2.属性绑定指令
- v-bind:属性绑定指令
例子:
<input type="text" v-bind:placeholder="tips">
<!-- 简写形式-->
<!--<input type="text" :placeholder="tips">-->
data: {
tips: '请输入用户名'
}
由于v-bind:使用次数很多,官方推荐简写形式(:)就是一个冒号
内容渲染指令与属性绑定指令也能进行简单运算
3.事件绑定指令
- v-on:事件绑定指令
<p>{{count}}</p>
<button v-on:click="addCount">+1</button>
<!--<button @click="addCount">+1</button>-->
var vm = new Vue({
el: '#app',
data: {
count: 1
},
methods: {
addCount(){
this.count += 1
}
}
})
可以在方法里使用this.数据去访问数据
v-on的简写属性@
事件可以传递参数,当不传递参数时,方法默认有一个参数,参数是事件对象,事件对象里面的target属性代表事件源对象,可以利用事件源对象改变背景颜色之类的。
当我们传递参数时,事件对象会被覆盖。那我们就是想传参,又想拿到事件对象,那么传递参数时,必须传递另外的参数,参数是固定写法$event
<button @click="addCount(1,$event)">+1</button>
methods: {
addCount(n,e){
...
}
}
4.数据双向绑定指令
注意:上面的指令都只能数据渲染视图,不能视图渲染数据,只有数据双向绑定才能完成
- v-model
v-model只能和表单数据绑定,因为只有表单元素才能给用户修改
5.条件渲染指令
- v-if
- v-show
区别:v-if:每次都是动态的创建元素或删除元素;v-show只是将其display:none而已
v-if配套使用:v-if,v-else-if,v-else
6.列表渲染指令
- v-for
<div id="app">
<p v-for="(item,index) in list" :key="item.id">id是{{item.id}},姓名是{{item.name}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
list:[
{id: '1',name: 'zhangsan'},
{id: '2',name: 'lisi'}
],
}
})
</script>
其中list是要循环的数组,item是循环中的每一个对象
v-for还支持v-for="(item,index) in list" 其中index为循环的索引,从0开始
官方强烈要求只要使用到了v-for,就必须为每一个循环项添加属性key,而且必须每一个是唯一的,推荐使用id作为key,不能使用索引index作为key
4.Vue过滤器
Vue过滤器在Vue3.0已经被淘汰,但是在Vue2.0版本还能使用。
Vue过滤器只能使用在插值表达式和属性绑定指令中,过滤器本质是一个函数,通过“管道符”调用。管道符前面表示是这个过滤器(函数)的参数。过滤器函数中必须return值
<div id="app">
<p>{{message | capi}}</p>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "nihao"
},
// 过滤器必须写在filters节点下
filters: {
capi(val){
return val.toUpperCase();
}
}
})
</script>
1.私有过滤器(如上图)
2.全局过滤器
Vue.filter('capi',(val) => {
return val.toUpperCase();
})
// 全局过滤器
// 第一个参数为过滤器的名称
// 第二个参数为过滤器函数处理
注意事项:如果全局过滤器与私有过滤器一致,那么优先调用私有过滤器。 过滤器也可以连续调用。
5.Watch监听器
监听器意为:监听数据的变化,只要数据一变化,就发生某些操作,监听器必须写在watch节点下;监听器本质也是函数。
<div id="app">
<input type="text" v-model="username">
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
username: ''
},
watch: {
// 第一个参数为新的值,第二个参数为旧的值
username(newval,oldval){
console.log('n:'+newval+',o:'+oldval)
}
}
})
</script>
监听器函数必须写在watch节点下,监听哪个数据,函数名就写那个数据名。
但是我们发现这个监听器函数必须在数据发生变化才会触发函数,我们想页面一刷新就触发一次函数怎么办?
其实监听器格式有2种:
- 方法监听器(也就是上面那种,不能页面刷新触发,也不能深度监听)
- 对象监听器(好处 1.就是可以在immediate情况下,页面一刷新就触发 2.可以实现深度监听,当监听的是一个对象时,里面的属性变化也能监听到)
<div id="app">
<input type="text" v-model="username">
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
username: ''
},
watch: {
username: {
handler(newval,oldval){
console.log('数据刷新');
},
// 是否立即触发,true表示触发
immediate: true,
// 深度监听
deep: true
}
}
})
</script>
6.计算属性
计算属性的本质是属性,但是定义时,是一个函数。通常可以对原来的属性进行计算,得到一个新的属性。
计算属性定义在computed节点下
<div id="app">
<p>{{newmsg}}</p>
</div>
<script>
new Vue({
el:"#app",
data: {
msg: "hi"
},
computed: {
newmsg(){
return this.msg + "hao"
}
}
})
</script>
7.基于Vue-cli搭建webpack脚手架项目
npm i @vue/cli -g
搭建项目脚手架:
vue create 文件夹名
看看Vue脚手架项目的结构及项目组成
node_moudel: 项目所依赖的包
public文件夹:项目首页index
src–assets:静态文件
--components:组件文件夹
--App.vue :组件
--main.js :入门文件
main.js内容:
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app') // 这里与el:“#app”一样的效果
意思是将App组件引入到index的#app中
什么是组件
组件就是把可以重复使用的UI界面,js函数封装以便下次使用。
在Vue项目中,以.vue结尾的文件都是组件。
组件组成部分:《template》《script》《style》
声明组件:
<template>
<p>{{msg}}</p>
</template>
<script>
export default {
data(){
return {
msg: "1234"
}
}
}
</script>
<style lang="less" scoped>
p {
color: red;
}
</style>>
注意事项
- template中只能有一个根节点
- script标签中data是函数,在return中返回对象
使用组件
- 导入组件
- 注册组件
- 使用组件
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
// 使用组件
<Test></Test>
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
// 导入组件
import HelloWorld from './components/HelloWorld.vue'
import Test from '@/components/Test.vue'
export default {
name: 'App',
// 注册组件
components: {
HelloWorld,
Test
}
}
</script>
自定义属性:我们再封装好组件后,希望调用方传递参数过来给组件使用,就用到了自定义属性。
export default {
name: 'App',
// 自定义属性
props: ['init']
// 注册组件
components: {
HelloWorld,
Test
}
}
注意事项
props属性是只读属性,不能修改。(将其值赋给data里面的值,就能修改)
export default {
name: 'App',
// 自定义属性
props: ['init']
data(){
return {
num: this.init
}
}
}
自定义属性的默认值
当调用方不传递参数的时候,自定义属性的值是undefined。那么默认值怎么设置?
export default {
name: 'App',
// 自定义属性
// 默认值是0
props: {
init: {
default: 0
}
}
data(){
return {
num: this.init
}
}
}
规定自定义属性的类型以及必填项
可以要求调用方传递参数的类型以及调用方调用组件时,必须传递其参数
export default {
name: 'App',
// 自定义属性
// 默认值是0
props: {
init: {
default: 0,
// 规定参数类型
type: Number,
// 规定必须传递参数
required: true
}
}
data(){
return {
num: this.init
}
}
}
scoped属性
<style lang="less" scoped>
#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>
加入了scoped属性表示里面的css样式只有在当前这个组件里面其作用,不会影响到别的组件。
那么当我们在组件里,引用了别的第三方组件,想修改子组件的样式,可以使用deep。
<style lang="less" scoped>
/deep/ h5 {
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>
8.组件的生命周期函数
组件创建周期:
- beforeCreate():组件的props/data/methods都尚未被创建,都处于不可用的状态。
- created():组件的props/data/methods已经创建好,都处于可使用的状态,但是组件的模板结构尚未生成。(不能使用页面中的Dom元素)(适合发起ajax请求)
- beforeMount():把数据和模板渲染到内存中,也不能操作Dom元素
- mounted():数据和模板从内存中渲染到浏览器中,可以操作Dom元素
组件使用周期:
- beforeUpdate():当页面中的data数据发生变化时(ajax请求,表单数据双向绑定),在页面会重新渲染数据之前的函数。
- updated():页面已经重新渲染好了数据。
组件销毁周期:
- beforeDestroy():将要销毁此组件,此时还处于正常状态,组件还在正常工作中。
- destroy():组件已经销毁
9.Vue组件之间传值
父子之间传值
父向子传值:
就是利用props属性传值。
子组件写props属性,父组件在使用子组件的时候利用属性绑定v-bind:绑定props属性
子组件:
<template>
<p>{{msg}}</p>
</template>
<script>
export default {
props: {
msg:{}
}
}
</script>
父组件:
<template>
<div id="app">
<input type="text" v-model="username">
<Test :msg="username"></Test>
</div>
</template>
<script>
import Test from '@/components/Test.vue'
export default {
name: 'App',
data() {
return {
username: 'zs'
}
},
components: {
Test
}
}
</script>
子向父传值:
子组件向父组件传值需要使用到自定义事件
// vm.$emit( 自定义事件的名称,自定义事件处理程序需要的参数1,参数2,参数3)
vm.$emit( 'aa' )
子组件:
<template>
<div>
<p>{{ msg }}</p>
// 子组件定义点击函数
<button @click="son">按钮</button>
</div>
</template>
<script>
export default {
data() {
return {
msg: "hello vue",
};
},
methods: {
son() {
console.log(this.msg);
// 激活自定义事件,参数一:事件名称,参数二: 传递参数
this.$emit("give", this.msg);
},
},
};
</script>
父组件:
<template>
<div id="app">
<p>{{username}}</p>
// 使用子组件时,自定义函数,前面give指的是事件名称,后面指的是事件触发函数
<Son @give="give"></Son>
</div>
</template>
<script>
import Son from '@/components/Son.vue'
export default {
name: 'App',
data() {
return {
username: ''
}
},
components: {
Son
},
methods: {
// 使用自定义函数
give(val){
this.username = val;
}
}
}
</script>
兄弟之间传值
在Vue2.0中,兄弟之间传值需要用到EventBus.js作为中间人。
使用步骤:
- 创建eventBus.js模块,并向外共享一个Vue实例对象
- 在数据发送方,调用bus.$emit(‘事件名称’,发送的数据)
- 在数据接收方,调用bus.$on(‘事件名称’,‘接受到数据要处理的函数’)
eventBus.js
import Vue from 'vue'
export default new Vue()
数据发送方:
<template>
<button @click="send">发送</button>
</template>
<script>
import Bus from '@/components/eventBus.js'
export default {
data(){
return {
msg: 'nihao'
}
},
methods: {
send(){
Bus.$emit('send',this.msg)
}
}
}
</script>
<style>
</style>
数据接收方:
<template>
<p>{{msgfromleft}}</p>
</template>
<script>
import Bus from '@/components/eventBus.js'
export default {
data(){
return {
msgfromleft:''
}
},
created(){
Bus.$on('send',(val) => {
this.msgfromleft = val
})
}
}
</script>
<style>
</style>
10.refs引用
由于Vue不推荐操作Dom元素,但是有些情况必须操作Dom元素。所以Vue里内置了 r e f s 对 象 。 refs对象。 refs对象。refs默认是一个空对象。
当给元素赋值ref属性时就能拿到该Dom元素:
<template>
<p ref="myp">{{msg}}</p>
<button @click="changecolor"></button>
</template>
<script>
export default {
data(){
return {
msg:''
}
},
methods: {
changecolor(){
this.$refs.myp.style.color="red"
}
}
}
</script>
同理:也能拿到组件Vue。
11.this.$nextTick(callback)方法
组件的$nextTick(callback)方法,会把回调函数里的方法延迟到Dom更新之后执行,从而保证回调函数里的方法能操作到最新的Dom元素。