vue.js基础学习——part01
Vue2文档https://v2.cn.vuejs.org/v2/guide/
Vue3文档https://cn.vuejs.org/guide/introduction.html
01 vue基础知识
1.vue使用
- 创建vue实例
- createApp表示创建一个Vue应用,存储到app这个变量里面,它里的参数表示这个应用最外层的组件,应该如何展示
<div id="root"></div>
<script>
//使用Vue创建一个应用实例,里面传递一些参数
const app = Vue.createApp({
data(){
return {message:'hello'}
},//原始数据
methods:{
handleItemClick(){
alert('click');
}
},//所有自定义方法
template:"<div v-on:click='handleItemClick'>{{message}}</div>"
});
//这个app只作用与id为root的元素身上
//vm代表的就是vue应用的根组件,可以利用vm操作数据
//例如:vm.$data.message = 'day';这样data里的message的值就修改为了day
const vm = app.mount('#root');
</script>
<div id="app">
<h1>用户名:<input type="text" v-model="name"/></h1> <br/>
<h1>您输入的用户名是: {{name}}</h1>
</div>
<script>
//创建一个Vue对象
var app = new Vue({
//指定,该对象代表<div id="app">,也就是说,这个div中的所有内容,都被当前的app对象管理
el: "#app",
//定义vue中的数据
data: {
message: "Hello world"
}
});
</script>
mvvm设计模式 m:model数据 v:view视图 vm:viewModel视图数据连接层
2.vue生命周期函数
- beforeCreate() 在实例生成之前会自动执行的函数
- created() 在实例生成之后会自动执行的函数
- beforeMount() 在组件内容被渲染到页面之前自动执行的函数
- mounted() 在组件内容被渲染到页面之后自动执行的函数
- beforeUpdate() 当数据发生变化时会立即自动执行的函数
- updated() 当数据发生变化,页面重新渲染后,会自动执行的函数
- beforeUnmount() 当Vue应用失效时,自动执行的函数
- unmounted() 当vue应用失效时,且dom完全销毁之后,自动执行的函数
3.常用指令介绍
1)文本插值
最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号),可以在里面写js表达式。
2)v-html
将内容解析为标签,而不是纯文本
<script>
data(){
return {
message:'<strong>hello</strong>'
}
}
</script>
//会将message中的内容解析成html标签
<div v-html="message"></div>
3)v-bind
为元素动态绑定一个属性,语法糖形式,只写一个冒号,:属性
若属性名是动态变化的,可以用中括号括起来::[属性]
data(){
return {
name:id
}
}
<div v-bind:id="index">{{message}}</div>
<div v-bind:[name]="index">{{message}}</div>
4)v-once
只使用一次变量的值,以后该变量的值发生改变,也不会渲染到dom上。
5)v-if
根据表达式的真假决定是否显示元素
为false时连同dom节点一起隐藏,也就是不占位隐藏
6)v-show
功能与v-if相同
区别是:v-show是占位隐藏
7)v-on
可以进行事件绑定,语法糖形式:@事件名
事件名是动态的话:@[事件名]
<div v-on:click = "handleclick">点击</div>
//也可以@click = "handleclick"
修饰符
阻止默认事件 .prevent(可以阻止跳转到百度的事件,而去执行我们定义的handleclick事件)
<form action="https://www.baidu.com" @click.prevent = "handleclick">
<button type = "submit">提交</button>
</form>
事件修饰符
- 在自定义方法中,我们想要传递一个形参,同时想获取到原生的事件对象的时候,可以再该方法中传递 一个$event变量。
- 想要实现一个事件执行多个方法时,如下:用逗号,隔开,并且括号不能省略
<div @click="handleClick1(),handleClick2()">btn</div>
- 修饰符
// 单击事件将停止传递,不会执行handleClick事件
<div @click="handleClick">
<a @click.stop="doThis"></a>
</div>
// 仅当 event.target 是元素本身时才会触发事件处理器
// 例如:事件处理器不来自子元素 ,只有点击你好时才会触发doThat事件,点击button时不会触发
<div @click.self="doThat">
你好
<button @click="handleBtn">button</button>
</div>
// 添加事件监听器时,使用 `capture` 捕获模式
// 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理
<div @click.capture="doThis">...</div>
// 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成
// 以防其中包含 `event.preventDefault()`
<div @scroll.passive="onScroll">...</div>
按键修饰符
Vue 为一些常用的按键提供了别名:
- .enter
- .tab
- .delete (捕获“Delete”和“Backspace”两个按键)
- .esc
- .space
- .up
- .down
- .left
- .right
//仅会在 $event.key 为 'PageDown' 时调用事件处理。
<input @keyup.page-down="onPageDown" />
8)动态绑定样式
- 可以给v-bind:class=“style”,style可以是一个动态的值,style改变,样式也就跟着改变
- 根据对象来控制样式的改变
//active为属性名,isActive是一个布尔值,控制active是否显示
<div :class="{ active: isActive }"></div>
<div :class="{ red: true,green: false }"></div>
- 根据数组来控制样式的改变
data(){
return {
redClass:'red',
greenClass:'green',
obj:{
pink:false,
black:true
}
}
}
<div v-bind:class="[redClass, greenClass,obj]"></div>
//渲染为:<div class="red green black"></div>
9)绑定内联样式
- 字符串形式
data(){
return {
styleString:'color:yellow;font-size:32px;'
}
}
<div v-bind:style="styleString">aaa</div>
- 对象形式(推荐)
data(){
return {
styleObj:{
color:'red',
background:'white'
}
}
}
<div v-bind:style="styleObj">aaa</div>
10)v-for
用来进行列表渲染,语法:v-for=“item in list”,list为要进行循环渲染的数据源,item是list中每一项数据,是迭代项的别名。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一key属性:
- 循环数组,也支持使用可选的第二个参数表示当前项的位置索引。
data(){
return {
list:[1,2,3,4]
}
}
//item是数组中的每一个数据项,index表示当前项的索引
<div v-for="(item,index) in list" :key={{index}}>
<div>{{item}}--{{index}}</div>
</div>
- 循环对象,第二个参数表示属性名 (例如 key),第三个参数表示位置索引
data(){
return {
listObj:{
name:'zs',
age:15,
sex:'male'
}
}
}
//value是对象中的每一个value值,可选的第二个参数key是当前项的对象名,可选的第三个参数index表示当前项的索引
<div v-for="(value,key,index) in listObj">
<div>{{value}}--{{key}}--{{index}}</div>
</div>
11)v-model
v-model可以实现双向绑定
- input textarea checkbox(1:绑定一个布尔值,2:绑定一个空数组,选择哪个,哪个就会添加到空数组中) radio(用法与checkbox相同,不过用字符串来接收,而不是数组) select
data(){
return {
message:'hello',
checked:false,
checkedValue:[],
selectedVal:''
}
}
//可以实现将message双向绑定到input上,两个值同步变化
{{message}}
<input v-model="message"/>
//checkbox 使用v-model
{{checked}}
<input type="checkbox" v-model="checked"/> //选中则checked变为true,取消选择checked变为false
//点击哪个,checkedValue就显示出哪个的value值
{{checkedValue}}
<input type="checkbox" v-model="checkedValue" value="zs"/>
<input type="checkbox" v-model="checkedValue" value="wmz"/>
<input type="checkbox" v-model="checkedValue" value="ly"/>
//select的双向绑定 selecte上添加multiple属性就成了多选的下拉列表,这时候selectedVal就需要定义成数组形式
<select V-model="selectedVal">
<option value="" disabled>请选择内容</option>
<option value="A">A</option>
<option value="B">B/option>
<option value="C">C</option>
</select>
指令修饰符:.lazy(input实现双向绑定后,不会立即跟着变化) .number(做类型转换) .trim(去除字符串前后的空格)【仅限于form表单上添加v-model】
Vue与微信小程序实现双向绑定的区别
4.数据(data)、方法(methods)、计算属性(computed)和侦听器(watch)
1)data
2)methods
我们自定的事件/方法都要写在methods中,methods中的this统一指向vue组件的实例(可以用this指向data中的数据,或者methods中的方法),但是这个事件/方法写成箭头函数的形式的话,this的指向就变了。
有return返回值的函数可以当做一个值来使用
data(){
return {
message:'hello world'
}
},
methods:{
formatString(str){
return string.toUpperCase(str)
}
},
template:`
<div>{{formatString(message)}}</div>
`
3)computed计算属性
计算属性是由依赖关系缓存计算出来的,当他的依赖发生变化时,计算属性也自动跟着变化。
methods与computed的区别
methods只要页面重新渲染,methods就会重新计算/执行
computed当计算属性的依赖的内容发生变化时,才会重新执行计算
4)watch侦听器
监听某些数据的改变,可以做一些异步的操作。(在状态变化时执行一些操作:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。)
data(){
return {
num:1
}
}
watch(){
num(newValue,oldValue){
console.log(newValue,oldValue)
}
}
tip:
- computed和methods都能实现的一个功能,建议使用computed,因为有缓存
- computed和watcher都能实现的功能,建议使用computed,因为更简洁
5)$nextTick
语法:this.$nextTick(回调函数)
- 在下一次DOM更新结束后执行其指定的回调
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作,要在nextTick所指定的回调函数中执行
5.自定义指令
一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。
<script>
//全局自定义指令
ript>
Vue.directive('fbind',{
bind(element,binding){
// 指令与元素成功绑定时(一上来)
console.log('bind')
console.log(element)
console.log(binding)
element.value = binding.value
},
inserted(element,binding){
// 指令所在元素被插入页面时
console.log('inserted')
console.log(element)
console.log(binding)
element.focus() //自动获取焦点
},
update(element,binding){
// 指令所在的模板被重新解析时
console.log('update')
element.value = binding.value
}
})
const app = Vue.createApp({
data() {
return { n: 1 }
},
directives:{
//指令回调里的this是window
//不推荐驼峰式
// 1.函数形式(绑定时元素并没有被放进页面上)
// big()函数何时会被调用:1.指令与元素成功绑定时(绑定了并不代表元素被放进页面上去了),2.指令所在的模板被重新解析时。(其实是bind()与update()的合写)
big(element,binding){
// console.log(binding)
//console.log(this) //this是window
element.innerText = binding.value * 10
},
// 对象形式
bd:{
bind(element,binding){
// 指令与元素成功绑定时(一上来)
console.log('bind')
console.log(element)
console.log(binding)
element.value = binding.value
},
inserted(element,binding){
// 指令所在元素被插入页面时
console.log('inserted')
console.log(element)
console.log(binding)
element.focus() //自动获取焦点
},
update(element,binding){
// 指令所在的模板被重新解析时
console.log('update')
element.value = binding.value
}
}
},
methods: {
handleAdd() {
this.n++
}
},
template: `
<div>
<h3>获取到的值:<span v-text="n"></span></h3>
<h3>放大十倍后的值:<span v-big="n"></span></h3>
<input type="text" v-bd:value="n">
<button @click="handleAdd">加法</button>
</div>
`
})
const vm = app.mount('#root')
</script>
6.过滤器
7.小知识
- v-once 写在标签上,可以让某个元素标签只渲染一次
- ref 在某个标签/子组件上写上ref=“name”,实际上是获取DOM节点,写在组件身上时,可以调用子组件里所有方法,某个标签上添加ref可以获取到该DOM元素
<h1 ref="title">你好</h1>
<Hello ref="com1"/>
console.log(this.$resf.title) //<h1 ref="title">你好</h1>
this.$refs.com1.sayHello()
- 父组件 孙子组件传值:provide(父组件)、inject(孙组件)
02 Vue组件
1.全局组件
组件具有复用性
2.局部组件
3.组件间传值
1)父组件给子组件传值
通过prop父组件向子组件传值。父组件引用子组件时,通过属性形式传递值给子组件,在子组件中通过prop注册传递的这个值。(传值时,值的name最好不要使用驼峰命名法,如果name比较长,可以使用短横-的方式来定义,比如:data-abc=“num”,而在子组件中接收时要使用驼峰式来接收,上面例子接收时为dataAbc)
props注册传递过来的值时,可以限制该值的类型等,如下:
- NON-prop属性:
1.父组件使用子组件向子组件传值时,如果在子组件不使用props注册该值,则如下: msg1和msg2属性就会自动添加到子组件HelloWorld的根元素上,即h4标签身上。
2.如果我们不想让这个属性自动添加到根元素上,可以在子组件的选项中设置 inheritAttrs: false。
3.使用场景:可以传递一个样式给子组件
<script>
// 定义局部组件
const HelloWorld = {
//inheritAttrs: false,
data() {
return {}
},
template: `<h4>子组件</h4>`
}
//1.创建应用实例
const app = Vue.createApp({
components: { HelloWorld },// 引入局部组件
template: `
<div id="id1">
<HelloWorld msg1="msg1" msg2="msg2" style="color:red;"/>
</div>`
})
//2.将实例挂载到id为root的元素身上
const vm = app.mount('#root')
</script>
3.当子组件中有多个根节点时,则以上效果不起作用,这时需要借助到v-bind=“$attrs” ,在想要生效的根节点上使用
单向数据流的理解
父组件传递给子组件的数据,能使用该数据,但子组件不能进行修改。
2)父子组件间通过事件传值
子组件向父组件传值
在子组件的标签上自定义一个事件,通过this.$emit()传递参数对象,然后在父组件中接收。
例子:父组件传递给子组件一个数据1,想要实现点击子组件使得该值加1,而props的值是只读的,所以需要进行父子组件间通信,点击子组件触发父组件做加法。
注:
- this. $emit()中可接收多个,第一个参数为要触发的事件名,之后的参数为携带的数据(可以是子组件想要传递给父组件的数据),在父组件中可以接受到。
v-model 可以在组件上使用以实现双向绑定
this.$emit(“input”,{})参考https://blog.csdn.net/weixin_50367873/article/details/109697556
4.插槽和具名插槽——slot
1)插槽的基本使用
- 使用子组件时用双标签,子组件中使用slot标签来占位,需要注意的是,slot标签上不能绑定事件,可以在slot标签外再包裹一个span来为slot的内容绑定事件。
- 父模板里调用的数据属性,使用的都是父模板里的数据。子模版里调用的数据属性,使用的都是子模版里的数据。
<script>
// 定义局部组件
const Counter = {
props:['modelValue'],
//slot组件中的内容是父组件没有给值时默认显示的内容,若父组件传值了,默认内容就不显示
template: `<div><slot>默认内容</slot></div>`
}
const app = Vue.createApp({
components: { Counter},// 引入局部组件
template: `
<Counter>你好</Counter>
<Counter>你是谁</Counter>`
})
const vm = app.mount('#root')
</script>
2)具名插槽
- 将插槽slot分为几个部分,给每个部分分别命名,使用的时候根据名称往里传不同的内容。
- 即slot 标签可以有一个特殊的 属性名name,用来给各个插槽分配唯一的 ID,以确定每一处要渲染的内容,没有提供 name 的 slot 出口会隐式地命名为“default”。
- 在向具名插槽提供内容的时候,我们可以在一个 template>元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。
3)作用域插槽
插槽的内容无法访问到子组件的状态。然而在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时将一部分数据提供给插槽。
4)具名作用域插槽
<script>
// 定义局部组件
const Counter = {
data(){
return {
msg:'我是子组件中的内容',
num:222
}
},
template: `
<div>
<slot name="slot1" :msg="msg"></slot>
<slot name="slot2" :num="num" counter="333"></slot>
</div>
`
}
const app = Vue.createApp({
components: { Counter},// 引入局部组件
data(){
return{ num:1}
},
template: `
<div>
<Counter>
<template v-slot:slot1="{msg}">
<div>{{msg}}</div>
</template>
<template #slot2="{num,counter}">
<div>{{num}}___{{counter}}</div>
</template>
</Counter>
</div>
`
})
const vm = app.mount('#root')
</script>
5.动态组件和异步组件
动态组件:根据数据的变化,结合component这个标签,来随时动态切换组件的显示。
03 VUE的过渡和动画
1.使用transition实现单元素的过渡和动画的效果
- 1使用transition标签将单元素/单组件包裹起来
<script>
const app = Vue.createApp({
data(){
return{ isShow:true}
},
methods:{
handleShow(){
this.isShow = !this.isShow
}
},
template: `
<transition>
<div v-show="isShow">Hello World</div>
</transition>
<button @click="handleShow">切换</button>
`
})
const vm = app.mount('#root')
</script>
//过渡
<style>
.v-enter-from{
opacity: 0;
}
/* v-enter-active v-leave-active 入场或离场的时间段 */
.v-enter-active{
transition: opacity 3s ease-in;
}
.v-leave-active{
transition: opacity 3s ease-out;
}
.v-enter-to{
opacity: 1;
}
/* 离开的起始状态 */
.v-leave-from{
opacity: 1;
}
/* 离开的终止状态 */
.v-leave-to{
opacity: 0;
}
</style>
<style>
/* 动画 */
@keyframes shake {
0%{
transform: translateX(-100px);
}
50% {
transform: translateX(-50px);
}
100% {
transform: translateX(50px);
}
}
/* v-enter-active v-leave-active 入场或离场的时间段 */
.v-enter-active{
animation: shake 3s;
}
.v-leave-active{
animation: shake 3s;
}
</style>
2.使用transition实现单元素的过渡和动画的效果(使用第三方动画库)
- transition标签有一个type属性,值可以为animation或transition,为animation时意思是过渡和动画的效果以动画的时间为准,动画的时间到了,过渡的效果也立马结束。反之亦然。
- duration
<transition :duration="1000"></transition> //意思是动画和过渡的时间不管多长,在1s后都结束
<transition :duration="{enter:1000,leave:3000}"></transition> //意思是动画和过渡的时间不管多长,入场都在1s后结束,离场在3s后结束
3.js钩子函数实现动画
<script>
const app = Vue.createApp({
data() {
return { isShow: true }
},
methods: {
handleShow() {
this.isShow = !this.isShow
},
handleBeforeEnter(el) { //接收一个参数,表示元素
el.style.color = "red"
},
handleEnterActive(el,done) { //接收两个参数,el元素,done函数,表示动画结束
let interval = setInterval(() => {
if (el.style.color === "red") {
el.style.color = "blue"
} else {
el.style.color = "red"
}
}, 1000)
setTimeout(()=>{
clearInterval(interval)
done() //调用后标识动画已结束,才会执行@after-enter的handleAfterEnter()事件
},5000)
},
handleAfterEnter(){
alert("结束")
},
},
template: `
<transition @before-enter="handleBeforeEnter"
@enter="handleEnterActive"
@after-enter="handleAfterEnter">
<div v-show="isShow">Hello World</div>
</transition>
<button @click="handleShow">切换</button>
`
})
const vm = app.mount('#root')
</script>
4.单元素/单组件间的切换
注:也可以将transition中的两个div换成两个不同的组件
单组件也可以用如下方式切换:
<transition appear>
<component :is="component"/>
</transition>
data(){
return {component:'component-A'}
},
methods:{
handleClick(){
if(this.component == 'component-A'){
this.is = 'component-B'
}else{
this.is = 'component-A'
}
}
}
04使用vue脚手架
1.说明
- Vue 脚手架是 Vue 官方提供的标准化开发工具(开发平台)。
- 最新的版本是 4.x。
- 文档:https://cli.vuejs.org/zh/
2.安装具体步骤
1)安装npm的淘宝镜像,可以加快速度
npm config set registry https://registry.npm.taobao.org
2)安装vue cli
npm install -g @vue/cli
3)查看是否安装成功
vue -V //可查看vue cli的版本
如果出现vue不是内部命令,可查看笔记解决vue不是内部命令来解决
4)切换到要创建项目的目录,然后使用命令创建项目
vue create xxx //xxx为自己的项目名
(ctrl+模板字符串即可打开终端,vscode里面)
tips:vue.config.js配置文件:使用vue inspect > output.js可以查看到Vue脚手架的默认配置,使用vue.config.js可以对脚手架进行个性化定制,详情https://cli.vuejs.org/zh
05vue技术
mixin混入
vue插件
功能 :用于增强vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个及以后的参数是插件使用者传递的数据。
在src目录下创建一个插件文件:plugins.js
// 定义插件 plugins.js
export default {
install(Vue,a,b,c) {
// 然后可以定义各种功能
console.log(a,b,c)
// 1.添加全局的过滤器
Vue.filter('mySlice', function (value) { return value.slice(0, 4) })
// 2.定义一个全局的自定义指令
Vue.directive('fbind', {
bind(element, binding) {
// 指令与元素成功绑定时(一上来)
element.value = binding.value
},
inserted(element) {
// 指令所在元素被插入页面时
element.focus() //自动获取焦点
},
update(element, binding) {
// 指令所在的模板被重新解析时
element.value = binding.value
}
})
// 3.定义一个混入
Vue.mixin({
data() {
return {
x: 100,
y: 200
}
}
})
// 4.给Vue原型上添加一个方法(vm和vc就都能用了)
Vue.prototype.hello = () => { alert('你好') }
}
}
在main.js中引入并使用插件
import Vue from 'vue'
import App from './App.vue'
import plugins from './plugins' //引入插件
Vue.config.productionTip = false
Vue.use(plugins,a,b,c) //使用插件
new Vue({
render: h => h(App),
}).$mount('#app')
之后可以使用插件里定义的内容了
//App.vue
<template>
<div>
<h1 ref="title">你好啊</h1>
<button @click="showTest">测试hello方法</button>
<SchoolMes ref="hw"/>
</div>
</template>
<script>
import SchoolMes from './components/SchoolMes.vue'
export default {
name: 'App',
components: {
SchoolMes
},
methods:{
showTest(){
this.hello()
}
}
}
</script>
<style>
</style>
//子组件 SchoolMes.vue
<template>
<div>
学校:{{ name | mySlice }}
<br>
地址:{{ address }}
<br />
<input type="text" v-fbind:value="classname">
<br>
班级:{{ classname }}
<br>
混入的值:{{x}}
</div>
</template>
<script>
export default {
name: 'SchoolMes',
props: {
msg: String
},
data() {
return {
name: 'abcdefghjk',
address: 'beijing',
classname: '十一班'
}
}
}
</script>
<style scoped></style>
scoped
作用:让样式在局部生效,防止冲突
写法:< style scoped>
小知识:webStorage——localStorage、sessionStorage,这俩的增删改查的方法均相同,区别是:sessionStorage存储的内容会随着浏览器窗口的关闭而消失,localStorage存储的内容需要手动清除才会消失。