1.v-once,只渲染一次
<h1 v-once>{{message}}</h1>
2.v-html,按照html格式渲染
<h2 v-html="url"> {{ url }} </h2>
url : '<a href="http://www.baidu.com">百度一下</a>'
3.v-pre,不解析mustacche语法
<h1 v-pre>{{ message +' '+ name}}</h1>
4.v-cloak,vue渲染完后再显示mustache变量(项目中使用虚拟dom,一般用不到)
<style>
div[v-cloak]{
display: none;
}
</style>
<div id="app" v-cloak>
<h1>{{ message +' '+ name}}</h1>
</div>
5.v-bind对元素动态添加、移除类
<style>
.redClass{
color: red;
}
.greenClass{
color: gold;
}
.title{
font-size: 50px;
}
</style>
<h1 class="title" :class="{redClass: redClass,greenClass:greenClass}">{{ message +' '}}</h1>
data : {
message : 'hello Mr tree',
redClass : true,
greenClass : true
},
6.虚拟dom复用:
vue在对dom元素进行渲染的时候,会尽可能复用已经存在的元素,而不是重新创建
下面代码如果不加key,则切换登陆的时候,input框会保留原来的值,加key可让vue不复用元素
<div v-if="isShow">
<label for="account">账号登陆</label>
<input type="text" id="account" placeholder="账号登陆" key="account">
</div>
<div v-else>
<label for="tel">手机登陆</label>
<input type="text" id="tel" placeholder="手机登陆" key="tel">
</div>
<div @click="isShow=!isShow">切换登陆</div>
6.v-for遍历对象的键、值、索引:
<ul>
<li v-for="(item,key,index) in obj">{{ key }}.{{ item }}.{{index}}</li>
</ul>
7.Vue.set()/this.$set()响应式修改数据
Vue.set(app.arr,index,33)
this.$set(this.arr,index,6666)
//更深层次的数组对象
this.skuDataChildren.map((item,index)=>{
item.specValues.map((item2,index2)=>{
item2.statu=1
this.$set(this.skuDataChildren[index].specValues,index2,item2)
})
})
8.组件父传子
<div id="app">
<cpn :c-movies="movies" :c-message-last="message"></cpn>
</div>
props : {
cMovies : {
type : Array,
default(){
return ["无极","霸王别姬","英雄"]
},
},
cMessageLast : {
type : String,
default : '你好,李焕英',
required : true
}
},
9.组件子传父
<div id="app" >
<cpn @inc="inc" @dec="dec" :c-movies="movies" :c-message-last="message"></cpn>
</div>
//子组件methods
methods : {
inc(){
this.counter++
this.$emit("inc",this.counter)
},
dec(){
this.counter--
this.$emit("dec",this.counter)
}
},
//父组件methods
methods : {
inc(val){
console.log("父组件",val);
},
dec(val){
console.log(`父组件${val}`);
}
},
10.子组件props实时更新传递到父组件
1.v-bind绑定属性,再input监听
<div id="app" >
<h3>父组件num1:{{num1}}</h3>
<cpn @inc="inc" @dec="dec" :c-movies="movies" :c-message-last="message" :num1="num1" @childchange="childchange"></cpn>
</div>
//子组件
<h5>{{ num1 }}</h5>
<h5>dNum1 : {{ dNum1 }}</h5>
<input type="text" :value="dNum1" @input="clickChange">
//子组件methods
clickChange($event){
this.dNum1=$event.target.value
this.$emit("childchange",this.dNum1)
}
//父组件methods
childchange(val){
console.log(val);
this.num1=Number(val)
}
2.v-model双向绑定data内变量,再watch监听
//子组件
<input type="text" v-model="dNum1" >
//子组件data
data(){
return {
dNum1 : this.num1
}
},
//子组件watch
watch : {
dNum1(newValue,oldValue){
this.$emit("childchange",newValue)
}
},
11.el与template的区别
//最终vue会将template的内容代替el
new Vue({
el : '#app',
template : `
<div>
<h1>{{message}}</h1>
<button @click="btnclick">单击</button>
</div>
`,
data : {
message : 'hello,树先生'
},
methods: {
btnclick(){
console.log("click a btn");
}
},
})
12.webpack加载vue文件
npm install vue-loader vue-template-compiler -D
module : {
rules : [
{
test : /\.vue$/,
use : ["vue-loader"]
}
]
},
plugins : [
new VueLoaderPlugin()
],
13.vue-cli项目历史配置
C:\Users\Administrator\.vuerc
14.修改vue-cli webpack配置
1.指令:vue ui
2.node_modules里面的@vue文件夹里面的webpack.config.js
3.在项目主目录下创建vue.config.js,该配置文件将自动与@vue文件夹里面的webpack.config.js合并
15.路由设置history模式
const router=new createRouter({
history : createWebHistory(process.env.BASE_URL),
routes,
mode : 'history'
})
16.默认页重定向
const routes=[
{
path : '/',
redirect : '/about',
},
{
path : '/home',
component : Home,
},
{
path : '/about',
component : About
}
]
17.所有组件都继承自vue原型
所以Vue.prototype.$router=router后,组件内部能使用this.$router
18.路由守卫
//全局守卫
//前置钩子/前置守卫(guard)
router.beforeEach((to,from,next)=>{
console.log(from);
document.title=to.meta.title
console.log("前置");
next()
})
//后置钩子(hook)
router.afterEach((to,from)=>{
console.log("后置",to);
})
//路由独享守卫
const routes=[
{
path : '/home',
component : Home,
meta : {
title : '首页',
abc : 'abc'
},
beforeEnter: (to, from, next) => {
// ...
next()
}
},
]
//组件内守卫
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
/* 离开组件时,保留路由地址用,使得再次打开页面时显示离开时路由页面 */
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
19.keep-alive
保持组件存在,组件缓存,路由跳转时不被unmounted
注意:vue3的keep-alive方法不兼容vue2的组件
//生命周期函数activated与deactivated函数只有在keep-alive内有效
activated() {
console.log("actived");
this.$router.push(this.path)
},
deactivated() {
console.log("deactivated");
},
//exclude : 被匹配的内部组件不进行缓存
//include : 被匹配的内部组件进行缓存
<router-view v-slot="{ Component }">
<keep-alive exclude="User,Profile">
<component :is="Component" />
</keep-alive>
</router-view>
//缓存整个组件
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" v-if="$route.meta.keepAlive"></component>
</keep-alive>
<component :is="Component" v-if="!$route.meta.keepAlive"></component>
</router-view>
//路由配置
{
path : '/home',
component : allRoutes.Home,
meta : {
keepAlive : true
}
},
//配合记录scrollY,使页面保持原来位置
activated(){
this.$refs.scroll.refresh()
this.$refs.scroll.scrollTo(0,this.scrollY,0)
},
deactivated(){
this.scrollY=this.$refs.scroll.getScrollY()
},
20.路径别名
改完必须重新启动项目
module.exports = {
configureWebpack: {
resolve : {
alias : {
"assets" : "@/assets",
"components" : '@/components',
"views" : "@/views",
}
}
}
}
html内写法:
<img src="~assets/img/tabBar/p2.svg" alt="" style="width:30px;height:30px;">
21.组件内监听vuex值变化
可用于监听某组件元素异步加载后,记录在vuex内的变量值,然后组件内监听vuex的变量值做相应动作
例如:监听图片异步加载,修改页面scroll高度
子组件:
<img :src="detail.img" alt="" @load="imgLoad">
imgLoad(){
this.$store.commit("addImgLoadCount")
}
vuex:
state: {
imgLoadCount : 0
},
mutations: {
addImgLoadCount(state){
state.imgLoadCount++
}
},
其他组件监听:
watch: {
"$store.state.imgLoadCount"(newVal,oldVal){
console.log(newVal,oldVal,"组件监听");
this.$refs.scroll.refresh()
}
},
22.mixins
Mixin 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个 mixin 对象可以包含任意组件选项。当组件使用 mixin 对象时,所有 mixin 对象的选项将被“混合”进入该组件本身的选项。(官网原话)
//使用方法
//common/mixins.js
export const mixins={
mounted(){
console.log("混入对象执行");
}
}
//组件内引入
import { mixins } from "common/mixins"
data(){
return {
}
},
mixins : [mixins],
23.封装插件
1.编写组件 Toast.vue
<template>
<div class="toast" v-show="isShow">
<div>{{ msg }}</div>
</div>
</template>
<script>
export default {
name: 'Toast',
data(){
return {
msg : "",
isShow : false
}
},
methods : {
show(msg="nihao",duration=2000){
this.msg=msg
this.isShow=true
setTimeout(()=>{
this.isShow=false
this.msg=""
},duration)
}
}
}
</script>
<style scoped lang = "scss">
.toast{
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
div{
padding: 8px 10px;
color: #fff;
background-color: rgba($color: #000000, $alpha: 0.6);
}
}
</style>
2.编写封装文件 index.js,与组件同一个目录
import Toast from "./Toast"
import { createApp } from 'vue'
const obj={
install: function(app){
const toast=createApp(Toast)
const instance=toast.mount(document.createElement("div"))
document.body.appendChild(instance.$el)
app.config.globalProperties.$Toast=instance
}
}
export default obj
3.调用插件
this.$Toast.show()
24.px2vw
npm install postcss-px-to-viewport --save-dev
//postcss.config.js,与vue.config.js同目录
module.exports = {
plugins: {
"autoprefixer": {
path: ['./src/*']
},
"postcss-import": {},
"postcss-px-to-viewport": {
"viewportWidth": "375", //视窗的宽度,对应的是我们设计稿的宽度
"viewportHeight": "667", // 视窗的高度
"unitPrecision": 2, //指定`px`转换为视窗单位值的小数位数(很多时候无法整除)
"viewportUnit": "vw", //指定需要转换成的视窗单位,建议使用vw
"fontViewportUnit": 'vw',
"selectorBlackList": ['#nprogress'], //指定不转换为视窗单位的类
"minPixelValue": 1, // 小于或等于`1px`不转换为视窗单位
"mediaQuery": false, // 允许在媒体查询中转换`px`
//"exclude": [/TabBar/,/ItemList/]
},
}
}
25.项目布置到服务器
1.vue.config.js配置publicPath,否则css,js文件引用路径不对
module.exports={
publicPath : "./",
}
2.路由配置哈希模式,否则router-view页面显示空白
//router/index.js
const router = createRouter({
//history: createWebHistory(process.env.BASE_URL),
history: createWebHashHistory(process.env.BASE_URL),
routes
})
export default router
26.nextTick
vue内的Dom元素是异步更新的,改变data值后,Dom元素需要通过nextTick获取,否则得到的是原值
<div ref="msgDiv">{{msg}}</div>
<div v-if="msg2">Message got inside $nextTick: {{msg2}}</div>
this.msg = "Hello world."
this.$nextTick(() => {
this.msg2 = this.$refs.msgDiv.innerHTML
})
- 在Vue生命周期的
created()
钩子函数进行的DOM操作一定要放在Vue.nextTick()
的回调函数中
在created()
钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()
的回调函数中。与之对应的就是mounted()
钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
- 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进
Vue.nextTick()
的回调函数中。
27.vue-cli4在Vue上绑定原型链属性
//main.js
import * as echarts from 'echarts'
const app = createApp(App)
app.use(store).use(router)
app.config.globalProperties.$echarts = echarts
app.mount('#app')