常用Vue功能及语法
因为自己工作中容易遗忘语法,只是用于快速查看。其他不常用的就不列举了。为了快速使用
Vue没有基础的建议学完该视频:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=122&spm_id_from=pageDriver
- 计算属性-computed
- 监视属性-watch
- 绑定样式
1.绑定class样式-- 字符串写法
2.绑定class样式–数组写法
3.绑定class样式–对象写法
4.绑定style样式–数组写法
5.绑定style样式-标签写法 - 过滤器
- Vue组件传值
1.父传子
2.子传父
3.兄弟之间 - bus
4.PubSub - 没有必要写,自行查资料 - 配置代理服务器
- 插槽
1.默认插槽
2.具名插槽
3.作用域插槽 - Vuex
1.安装Vuex
2.使用Vuex规范
3.简单Vuex使用Demo
4.mapState,mapGetters,mapMutations,mapActions
5.Vuex模块化编码 - Vue-Router
1.query参数
2.params参数
3.路由的props配置
4.编程式路由导航
5.缓存路由组件
一、计算属性-computed
方式一、全写方式
computed:{
fullName:{
//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
get(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
},
//set什么时候调用? 当fullName被修改时。
set(value){
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
},
方式二、简写方式
computed:{
//简写
fullName(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
}
}
二、监视属性-watch
watch:{
//监视多级结构中某个属性的变化
'numbers.a':{
handler(){
console.log('a被改变了')
}
},
//监视多级结构中所有属性的变化
numbers:{
deep:true,
handler(newValue,oldValue){
console.log('numbers改变了')
}
}
}
三、绑定样式
适用于:样式的类名不确定,需要动态指定
<div class="basic" :class="mood" @click="changeMood">{{name}}</div>
changeMood(){
const arr = ['happy','sad','normal']
const index = Math.floor(Math.random()*3)
this.mood = arr[index]
}
.happy{
....省略
}
.sad{
....省略
}
适用于:要绑定的样式个数不确定、名字也不确定
<div class="basic" :class="classArr">{{name}}</div>
// Vue中
data:{
classArr:['class1','class2','class3'],
}
.class1{
...省略
}
.class2{
...省略
}
适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用
<div :class="classObj">{{name}}</div>
// Vue中
data(){
return{
classObj:{
class1:false,
class2:false,
},
}
}
.class1{
...省略
}
.class2{
...省略
}
<div :style="styleObj">{{name}}</div>
// Vue中
data:{
styleObj:{
fontSize: '40px',
color:'red',
}
}
<div :style="styleArr">{{name}}</div>
// Vue中
data:{
styleArr:[
{
fontSize: '40px',
color:'blue',
},
{
backgroundColor:'gray'
}
]
}
<div :style="[{'fontSize': '40px','color':'blue'}]">{{name}}</div>
四、过滤器
<!--方式一-->
<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
<!--方式二-->
<h3 :x="msg | mySlice"></h3>
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
// vue属性中
new Vue({
//局部过滤器
filters:{
timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
// console.log('@',value)
return dayjs(value).format(str)
}
}
})
五、Vue组件传值
1.父传子<template>
<!--父亲组件中-->
<Student name="李四" sex="女" :age="18" />
</template>
<script>
import Student from './components/Student'
export default {
name:'App',
components:{Student}
}
</script>
<template>
<div>
<h1>{{msg}}</h1>
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<h2>学生年龄:{{myAge+1}}</h2>
<button @click="updateAge">尝试修改收到的年龄</button>
<button @click="sendSchoolName">把学校名给App</button>
</div>
</template>
<script>
export default {
name:'Student',
data() {
return {
msg:'我是一个尚硅谷的学生',
myAge:this.age
}
},
methods: {
sendSchoolName(){
this.getSchoolName(this.name)
},
updateAge(){
this.myAge++
}
},
//简单声明接收
// props:['name','age','sex','getSchoolName']
//接收的同时对数据进行类型限制
/* props:{
name:String,
age:Number,
sex:String
} */
//接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
props:{
name:{
type:String, //name的类型是字符串
required:true, //name是必要的
},
age:{
type:Number,
default:99 //默认值
},
sex:{
type:String,
required:true
}
}
}
</script>
2.子传父
一、方式一 —— props
<template>
<!--父亲组件中-->
<Student :getSchoolName="getSchoolName"/>
</template>
<script>
import Student from './components/Student'
export default {
name:'App',
components:{Student},
methods: {
getSchoolName(name){
console.log('App收到了学校名:',name)
},
}
}
</script>
<template>
<div>
<h1>{{msg}}</h1>
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<h2>学生年龄:{{myAge+1}}</h2>
<button @click="sendSchoolName">把学校名给App</button>
</div>
</template>
<script>
export default {
name:'Student',
//简单声明接收
props:['getSchoolName'],
data() {
return {
msg:'我是一个学生',
myAge:this.age
}
},
methods: {
sendSchoolName(){
this.getSchoolName(this.name)
}
}
}
</script>
二、方式二 —— 绑定一个自定义事件(使用@或v-on)
<template>
<!--父亲组件中-->
<Student @getSchoolName="getSchoolName"/>
</template>
<script>
import Student from './components/Student'
export default {
name:'App',
components:{Student},
methods: {
getSchoolName(name,...params){
console.log('App收到了学校名:',name)
},
}
}
</script>
<template>
<!--子组件中-->
<div class="student">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<h2>当前求和为:{{number}}</h2>
<button @click="sendStudentlName">把学生名给App</button>
</div>
</template>
<script>
export default {
name:'Student',
methods: {
sendStudentlName(){
//触发Student组件实例身上的getSchoolName事件
this.$emit('getSchoolName',this.name,666,888,900)
},
unbind(){
this.$off('getSchoolName') //解绑一个自定义事件
// this.$off(['getSchoolName','demo']) //解绑多个自定义事件
// this.$off() //解绑所有的自定义事件
},
death(){
this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
}
},
}
</script>
三、方式三 —— 绑定一个自定义事件(使用ref)
<template>
<!--父亲组件中-->
<Student ref="student"/>
</template>
<script>
import Student from './components/Student'
export default {
name:'App',
components:{Student},
methods: {
getStudentName(name,...params){
console.log('App收到了学生名:',name,params)
this.studentName = name
},
},
mounted() {
this.$refs.student.$on('getStudentName',this.getStudentName) //绑定自定义事件
// this.$refs.student.$once('getStudentName',this.getStudentName) //绑定自定义事件(一次性)
},
}
</script>
<template>
<!--子组件中-->
<div class="student">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<h2>当前求和为:{{number}}</h2>
<button @click="sendStudentlName">把学生名给App</button>
</div>
</template>
<script>
export default {
name:'Student',
methods: {
sendStudentlName(){
//触发Student组件实例身上的getSchoolName事件
this.$emit('getSchoolName',this.name,666,888,900)
},
unbind(){
this.$off('getSchoolName') //解绑一个自定义事件
// this.$off(['getSchoolName','demo']) //解绑多个自定义事件
// this.$off() //解绑所有的自定义事件
},
death(){
this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
}
},
}
</script>
3.兄弟之间 - bus
首先在main.js中挂载出全局bus
//创建vm
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线
},
})
接下来使用如下:
<template>
<div>
<!--兄弟组件 一-->
<button @click="sendStudentName">把学生名给School组件</button>
</div>
</template>
<script>
export default {
name:'Student',
data() {
return {
name:'张三'
}
},
methods: {
sendStudentName(){
this.$bus.$emit('hello',this.name)
}
},
}
</script>
<template>
<!--兄弟组件 二-->
</template>
<script>
export default {
name:'School',
data() {
return {
name:'张三'
}
},
mounted() {
// console.log('School',this)
this.$bus.$on('hello',(data)=>{
console.log('我是School组件,收到了数据',data)
})
},
beforeDestroy() {
this.$bus.$off('hello') // 组件销毁卸载事件
},
}
</script>
六、配置代理服务器
建立vue.config.js
module.exports = {
pages: {
index: {
//入口
entry: 'src/main.js',
},
},
lintOnSave:false, //关闭语法检查
//开启代理服务器(方式一)
/* devServer: {
proxy: 'http://localhost:5000'
}, */
//开启代理服务器(方式二)
devServer: {
proxy: {
'/atguigu': {
target: 'http://localhost:5000',
pathRewrite:{'^/atguigu':''},
// ws: true, //用于支持websocket
// changeOrigin: true //用于控制请求头中的host值
},
'/demo': {
target: 'http://localhost:5001',
pathRewrite:{'^/demo':''},
// ws: true, //用于支持websocket
// changeOrigin: true //用于控制请求头中的host值
}
}
}
}
七、插槽
1.默认插槽 <div class="category">
<h3>{{title}}分类</h3>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
</div>
使用如下
<Category title="美食" >
<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
</Category>
<div class="category">
<h3>{{title}}分类</h3>
<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
<slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
</div>
使用如下
<Category title="美食" >
<!--方式一-->
<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
<!--方式二-->
<template v-slot:footer>
<div class="foot">
<a href="http://www.atguigu.com">经典</a>
<a href="http://www.atguigu.com">热门</a>
<a href="http://www.atguigu.com">推荐</a>
</div>
<h4>欢迎前来观影</h4>
</template>
</Category>
<div class="category">
<!--category组件中绑定games:['红色警戒','穿越火线','劲舞团','超级玛丽']-->
<h3>{{title}}分类</h3>
<slot :games="games" msg="hello">我是默认的一些内容</slot>
</div>
使用如下
<div class="container">
<Category title="游戏">
<template scope="atguigu">
<ul>
<li v-for="(g,index) in atguigu.games" :key="index">{{g}}</li>
</ul>
</template>
</Category>
<Category title="游戏">
<template scope="{games}">
<ol>
<li v-for="(g,index) in games" :key="index">{{g}}</li>
</ol>
</template>
</Category>
<Category title="游戏">
<template slot-scope="{games}">
<h4 v-for="(g,index) in games" :key="index">{{g}}</h4>
</template>
</Category>
</div>
八、vuex
[什么是Vuex?](https://vuex.vuejs.org/zh/#%E4%BB%80%E4%B9%88%E6%98%AF-%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86%E6%A8%A1%E5%BC%8F)安装命令如下:
npm install vuex --save
js中使用如下:
import Vue from ‘vue’
import Vuex from ‘vuex’
Vue.use(Vuex)
state: 主要负责定义数据
action: 主要负责业务的逻辑处理,尽量不要直接对state处理,方法名尽量小写。接受参数(context,value)
mutations: 主要修改state中的值,不负责处理业务逻辑,方法名尽量大写。接受参数(state,value)
getters: 主要用于将state中的数据进行加工,与computed属性相似。接受参数(state)
.
流程如下:
组件中通过dispatch提交于action ——> action 中通过context.commit()提交 mutation ——> mutation 中对state进行修改 ——> Vue重新渲染组件
store定义如下:
//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions——用于响应组件中的动作
const actions = {
jiaOdd(context,value){
console.log('actions中的jiaOdd被调用了')
if(context.state.sum % 2){
context.commit('JIA',value)
}
},
jiaWait(context,value){
console.log('actions中的jiaWait被调用了')
setTimeout(()=>{
context.commit('JIA',value)
},500)
}
}
//准备mutations——用于操作数据(state)
const mutations = {
JIA(state,value){
console.log('mutations中的JIA被调用了')
state.sum += value
},
JIAN(state,value){
console.log('mutations中的JIAN被调用了')
state.sum -= value
}
}
//准备state——用于存储数据
const state = {
sum:0 //当前的和
}
//准备getters——用于将state中的数据进行加工
const getters = {
bigSum(state){
return state.sum*10
}
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
使用demo如下:
<template>
<div>
<h1>当前求和为:{{$store.state.sum}}</h1>
<h3>当前求和放大10倍为:{{$store.getters.bigSum}}</h3>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name:'Count',
data() {
return {
n:1, //用户选择的数字
}
},
methods: {
increment(){
// commit 用于提交 mutations
this.$store.commit('JIA',this.n)
},
decrement(){
this.$store.commit('JIAN',this.n)
},
incrementOdd(){
// dispatch 用于提交 actions
this.$store.dispatch('jiaOdd',this.n)
},
incrementWait(){
this.$store.dispatch('jiaWait',this.n)
},
},
mounted() {
console.log('Count',this)
},
}
</script>
4.mapState,mapGetters,mapMutations,mapActions
基于上面的store,使用如下:
<template>
<div>
<button @click="increment(n)">+</button>
<button @click="decrement(n)">-</button>
<button @click="incrementOdd(n)">当前求和为奇数再加</button>
<button @click="incrementWait(n)">等一等再加</button>
</div>
</template>
<script>
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
export default {
name:'Count',
computed:{
//借助mapState生成计算属性,从state中读取数据。(对象写法)
// ...mapState({he:'sum',xuexiao:'school',xueke:'subject'}),
//借助mapState生成计算属性,从state中读取数据。(数组写法)
...mapState(['sum','school','subject']),
/* ******************************************************************** */
//借助mapGetters生成计算属性,从getters中读取数据。(对象写法)
// ...mapGetters({bigSum:'bigSum'})
//借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
...mapGetters(['bigSum'])
},
methods: {
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
...mapMutations({increment:'JIA',decrement:'JIAN'}),
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
// ...mapMutations(['JIA','JIAN']),
/* ************************************************* */
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(数组写法)
// ...mapActions(['jiaOdd','jiaWait'])
},
}
</script>
5.Vuex模块化编码
前提:store下存在count.js与person.js两个文件。模块化编码namespaced:true必须编写
//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
import countOptions from './count' // count.js
import personOptions from './person' // person.js
//应用Vuex插件
Vue.use(Vuex)
//创建并暴露store
export default new Vuex.Store({
modules:{
countAbout:countOptions,
personAbout:personOptions
}
})
方式一、使用 …map 的方式
代码如下:
<template>
<div>
<button @click="increment(n)">+</button>
<button @click="decrement(n)">-</button>
<button @click="incrementOdd(n)">当前求和为奇数再加</button>
<button @click="incrementWait(n)">等一等再加</button>
</div>
</template>
<script>
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
export default {
name:'Count',
computed:{
//借助mapState生成计算属性,从state中读取数据。(数组写法)
...mapState('countAbout',['sum','school','subject']),
...mapState('personAbout',['personList']),
//借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
...mapGetters('countAbout',['bigSum'])
},
methods: {
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
}
}
</script>
方式二、通过 $store 使用
使用如下:
<template>
<div>
<button @click="add">添加</button>
<button @click="addWang">添加一个姓王的人</button>
<button @click="addPersonServer">添加一个人,名字随机</button>
</div>
</template>
<script>
import {nanoid} from 'nanoid'
export default {
name:'Person',
computed:{
personList(){
return this.$store.state.personAbout.personList
},
sum(){
return this.$store.state.countAbout.sum
},
firstPersonName(){
return this.$store.getters['personAbout/firstPersonName']
}
},
methods: {
add(){
const personObj = {id:nanoid(),name:this.name}
this.$store.commit('personAbout/ADD_PERSON',personObj)
},
addWang(){
const personObj = {id:nanoid(),name:this.name}
this.$store.dispatch('personAbout/addPersonWang',personObj)
},
addPersonServer(){
this.$store.dispatch('personAbout/addPersonServer')
}
},
}
</script>
九、Vue-Router
[Vue-Router官网](https://router.vuejs.org/zh/guide/essentials/dynamic-matching.html#%E5%93%8D%E5%BA%94%E8%B7%AF%E7%94%B1%E5%8F%82%E6%95%B0%E7%9A%84%E5%8F%98%E5%8C%96)格式如下:
// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//创建并暴露一个路由器
export default new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component:About
},
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News,
},
{
path:'message',
component:Message,
children:[
{
name:'xiangqing',
path:'detail/:id/:title',
component:Detail,
}
]
}
]
}
]
})
标签使用格式如下:
<!--字符串模板方法-->
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title</router-link>
<!--to的对象写法-->
<router-link :to="{
name:'xiangqing' // 指定的路由name,就不必写path那么长了
// path:'/home/message/detail',
query:{
id:1,
title:"你好"
}
}">
获取query参数,格式如下:
<li>消息编号:{{$route.query.id}}</li>
<li>消息标题:{{$route.query.title}}</li>
标签使用格式如下:
(注坑:使用params时使用name属性,不要使用path属性,否则找不到页面)
<!-- 跳转路由并携带params参数,to的字符串写法 -->
<router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link>
<!-- 跳转路由并携带params参数,to的对象写法 -->
<router-link :to="{
name:'xiangqing',
params:{
id:m.id,
title:m.title
}
}">
</router-link>
获取params参数,格式如下:
<li>消息编号:{{$route.params.id}}</li>
<li>消息标题:{{$route.params.title}}</li>
router.js中写法如下:
{
path:'message',
component:Message,
children:[
{
name:'xiangqing',
path:'detail',
component:Detail,
//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
// props:{a:1,b:'hello'}
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
// props:true
//props的第三种写法,值为函数
// props({query:{id,title}})
props($route){
return {
id:$route.query.id,
title:$route.query.title,
a:1,
b:'hello'
}
}
}
]
组件中写法如下:
<template>
<ul>
<li>消息编号:{{id}}</li>
<li>消息标题:{{title}}</li>
</ul>
</template>
<script>
export default {
name:'Detail',
props:['id','title'],
}
</script>
4.编程式路由导航
1.query方式
this.$router.push({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
2.replace方式
this.$router.replace({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
3.params方式
this.$router.push({
name:'xiangqing',
params:{
id:m.id,
title:m.title
}
})
4.后退前进
this.$router.back() // 后退
this.$router.forward() // 前进
this.$router.go(3) // 前进3步
this.$router.go(-3) // 后退3步
<!-- 缓存一个路由组件News,该路由下的其他组件不缓存 -->
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
…未完待续