Vue2基础
1. MVVM模型
MVVM 模型
1. M :模型 ( Model) :data中的数据
2. V :视图 ( View) :模板代码
3. VM :视图模型 ( ViewModel) :Vue实例
观察发现:
1 . data中所有的属性,最后都出现在了vm身上。
2 . vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。
MVVM 是vue实现数据驱动视图的和双向数据绑定的核心原理
Model表示渲染数据所依赖的数据源
View表示当前页面所渲染的DOM 结构
ViewModel表示vue的实例,是核心他把上面两者绑定在一起
2. vue中的数据代理
vue数据代理的原理
1 . Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/ 写)
2 . Vue中数据代理的好处:
更加方便的操作data中的数据
3. 基本原理:
通过Object. defineProperty ( ) 把data对象中所有属性添加到vm上。
为每一个添加到vm上的属性,都指定一个getter/ setter。
在getter/ setter内部去操作(读/ 写)data中对应的属性。
Object.defineProperty()实现数据代理
< body>
< ! -- 数组的响应 -- >
< input type= "text" id= "ipt" >
< p id= 'op' > < / p>
< ! -- 对象的响应 -- >
< input type= "text" id= "iptj" >
< p id= 'opj' > < / p>
< script>
function Observer ( obj ) {
const keys = Object. keys ( obj)
keys. forEach ( ( key ) => {
Object. defineProperty ( this , key, {
get ( ) {
console. log ( 'get方法被调用了' ) ;
return obj[ key]
} ,
set ( val) {
console. log ( 'set方法调用了' )
obj[ key] = val
}
} )
} )
}
const obs = new Observer ( [ 1 , 2 , 3 ] )
const ipt = document. querySelector ( '#ipt' )
ipt. value = obs[ 1 ]
document. querySelector ( '#op' ) . innerHTML = obs[ 1 ]
ipt. addEventListener ( 'input' , function ( e ) {
obs[ 1 ] = e. target. value
document. querySelector ( '#op' ) . innerHTML = obs[ 1 ]
} )
const obj = new Observer ( {
a : 1 , b : 2 } )
const iptj = document. querySelector ( '#iptj' )
iptj. value = obj. a
document. querySelector ( '#opj' ) . innerHTML = obj. a
iptj. addEventListener ( 'input' , function ( e ) {
obj. a = e. target. value
document. querySelector ( '#opj' ) . innerHTML = obj. a
} )
< / script>
< / body>
(1)vue2中数据代理数组
代理的数组无法触发响应
< template>
< div>
数组:{
{ arr }}
< br />
< button @click = " changeArr" > 改变数组</ button>
</ div>
</ template>
< script>
export default {
name : "School" ,
data ( ) {
return {
arr : [ ] ,
} ;
} ,
methods : {
changeArr ( ) {
this . arr[ 1 ] = 1 ;
} ,
} ,
} ;
</ script>
解决办法this.$set
< template>
< div>
数组:{
{ arr }}
< br />
< button @click = " changeArr" > 改变数组</ button>
</ div>
</ template>
< script>
export default {
name : "School" ,
data ( ) {
return {
arr : [ ] ,
} ;
} ,
methods : {
changeArr ( ) {
this . $set ( this . arr, 0 , 1 ) ;
} ,
} ,
} ;
</ script>
(2)vue2中数据代理对象
代理对象的问题(对象无初始值,vue3常用ref({}))
< template>
< div>
对象:{
{ obj }}
< br />
< button @click = " changeObj" > 改变对象</ button>
</ div>
</ template>
< script>
export default {
name : "School" ,
data ( ) {
return {
obj : {
A : "" ,
} ,
} ;
} ,
methods : {
changeObj ( ) {
this . obj. B = 2 ;
} ,
} ,
} ;
</ script>
代理对象的问题(对象有初始值)
< template>
< div>
对象:{
{ obj }}
< br />
< button @click = " changeObj" > 改变对象</ button>
</ div>
</ template>
< script>
export default {
name : "School" ,
data ( ) {
return {
obj : {
A : "" ,
} ,
} ;
} ,
methods : {
changeObj ( ) {
this . obj. A = 1 ;
} ,
} ,
} ;
</ script>
使用this.$set
< template>
< div>
对象:{
{ obj }}
< br />
< button @click = " changeObj" > 改变对象</ button>
</ div>
</ template>
< script>
export default {
name : "School" ,
data ( ) {
return {
obj : {
} ,
} ;
} ,
methods : {
changeObj ( ) {
this . obj. A = 1 ;
this . obj. B = 2 ;
this . obj. C = 3 ;
this . $set ( this . obj, "D" , 4 ) ;
} ,
} ,
} ;
</ script>
3. vue中常用的事件处理
常用的事件修饰符
< h1> Hello {
{name}}</ h1>
< a href = " https://www.baidu.com" @click.prevent = " showInfo" > 点我提示</ a>
< div class = " demo1" @click = " showInfo" > < button @click.stop = " showInfo" > 点我提示</ button> </ div>
< button @click.once = " showInfo" > 点我提示</ button>
< div class = " box1" @click.capture = " showMsg(1)" >
div1
< div class = " box2" @click = " showMsg(2)" >
div2
</ div>
</ div>
< div class = " demo1" @click.self = " showInfo" > < button @click = " showInfo" > 点我提示</ button> </ div>
< ul class = " list" @wheel.passive = " demo" >
< li> 1</ li>
< li> 2</ li>
< li> 3</ li>
< li> 4</ li>
</ ul>
</ div>
常用的按键修饰符
1 . Vue中常用的按键别名:
回车 => enter
删除 => delete ( 捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab ( 特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right
2 . Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab- case (短横线命名)
3. 系统修饰键(用法特殊):ctrl、alt、shift、meta ( win键)
( 1 ) . 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
( 2 ) . 配合keydown使用:正常触发事件。
( 3 ) . 系统修饰键可以组合ctrl. y
4. vue2中选项式属性
(1)计算属性
非响应式
computed : {
fullName ( ) {
return this . firstName+ '-' + this . lastName;
}
}
响应式
computed : {
fullName : {
get ( ) {
console. log ( "get被调用了" ) ;
return this . firstName+ '-' + this . lastName;
} ,
set ( value) {
console. log ( "set被调用了" ) ;
const arr= value. split ( '-' ) ;
this . firstName= arr[ 0 ] ;
this . lastName= arr[ 1 ] ;
}
}
}
(2)监听属性
监听的配置
watch : {
number : {
deep : true ,
immediate : true ,
handler ( ) {
console. log ( 'number改变了' ) ;
}
}
}
监听属性的属性方式
watch : {
isHot ( newValue, oldValue ) {
console. log ( 'isHot被修改了' , newValue, oldValue)
}
}
(3)生命周期
构造
beforeCreate ( ) {
} ,
created ( ) {
console. log ( this . n) ; } ,
挂载
beforeMount ( ) {
} ,
mounted ( ) {
console. log ( this . $el instanceof HTMLElement ) ; } ,
更新
beforeUpdate ( ) {
console. log ( this . $el ) ; } ,
updated ( ) {
} ,
卸载
beforeDestroy ( ) {
} ,
destroyed ( ) {
} ,
5. vue2的组合式实现
下载插件
yarn add unplugin- vue2- script- setup
yarn add @vue/ composition- api
使用组合式API插件和setup语法糖配置
import VueCompositionAPI from "@vue/composition-api" ;
Vue. use ( VueCompositionAPI) ;
const ScriptSetup = require ( 'unplugin-vue2-script-setup/webpack' ) . default
module. exports = {
parallel : false ,
configureWebpack : {
plugins : [
ScriptSetup ( {
} ) ,
] ,
} ,
}
简单使用
< template>
< div>
数组:{
{ arr }} 对象:{
{ obj }}
< br />
< button @click = " changeObj" ref = " a" > 改变对象</ button>
< button @click = " changeArr" > 改变数组</ button>
</ div>
</ template>
< script setup >
import {
ref } from "@vue/composition-api" ;
let arr = ref ( [ ] ) ;
let obj = ref ( {
} ) ;
const changeArr = ( ) => {
} ;
const changeObj = ( ) => {
} ;
</ script>
Vue2组件
1.常用内置组件
(1)component组件
< template>
< div>
< component :is = " component" > </ component>
< button @click = " changeFn" > 切换</ button>
</ div>
</ template>
< script>
import School from "./components/School.vue" ;
import Stu from "./components/Stu.vue" ;
export default {
name : "App" ,
components : {
School,
Stu,
} ,
data ( ) {
return {
component : "School" ,
} ;
} ,
methods : {
changeFn ( ) {
this . component === "Stu"
? ( this . component = "School" )
: ( this . component = "Stu" ) ;
} ,
} ,
} ;
</ script>
(2)transition组件
介绍
v- enter:定义进入过渡的开始状态 ( 开始状态和离开过度的结束状态一致)
v- enter- active:定义进入过渡生效时的状态 ( 写进入的动画)
v- enter- to:2.1 .8 版及以上定义进入过渡的结束状态。
v- leave:定义离开过渡的开始状态。
v- leave- active:定义离开过渡生效时的状态 ( 写离开的动画)
v- leave- to:2.1 .8 版及以上定义离开过渡的结束状态 ( 开始状态和离开过度的结束状态一致)
基本使用
< template>
< div>
< transition name = " fade" >
< School v-if = " flag" />
</ transition>
< button @click = " flag = !flag" > toggle</ button>
</ div>
</ template>
< script>
import {
School, Stu } from "./components" ;
export default {
name : "" ,
props : {
} ,
data ( ) {
return {
flag : true ,
} ;
} ,
components : {
School, Stu } ,
} ;
</ script>
< style>
.fade-enter-active,
.fade-leave-active {
transition : opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
opacity : 0;
}
.bounce-enter-active {
animation : bounce-in .5s;
}
.bounce-leave-active {
animation : bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform : scale ( 0) ;
}
50% {
transform : scale ( 1.5) ;
}
100% {
transform : scale ( 1) ;
}
}
</ style>
结合第三方动画库
< template>
< div>
< transition
enter-active-class = " animate__animated animate__bounceInDown"
leave-active-class = " animate__animated animate__bounceOutDown"
>
< School v-if = " flag" />
</ transition>
< button @click = " flag = !flag" > toggle</ button>
</ div>
</ template>
< script>
import {
School, Stu } from "./components" ;
import "animate.css" ;
export default {
name : "" ,
props : {
} ,
data ( ) {
return {
flag : true ,
} ;
} ,
components : {
School, Stu } ,
methods : {
} ,
watch : {
} ,
computed : {
} ,
} ;
</ script>
transition的构子函数
< template>
< div>
< transition
v-on: before-enter= " beforeEnter"
v-on: enter= " enter"
v-on: after-enter= " afterEnter"
v-on: enter-cancelled= " enterCancelled"
v-on: before-leave= " beforeLeave"
v-on: leave= " leave"
v-on: after-leave= " afterLeave"
v-on: leave-cancelled= " leaveCancelled"
>
< School v-if = " flag" />
</ transition>
< button @click = " flag = !flag" > toggle</ button>
</ div>
</ template>
< script>
import {
School, Stu } from "./components" ;
import "animate.css" ;
export default {
name : "" ,
props : {
} ,
data ( ) {
return {
flag : true ,
} ;
} ,
components : {
School, Stu } ,
methods : {
beforeEnter ( ) {
} ,
enter ( ) {
} ,
afterEnter ( ) {
} ,
enterCancelled ( ) {
} ,
beforeLeave ( ) {
} ,
leave ( ) {
} ,
afterLeave ( ) {
} ,
leaveCancelled ( ) {
} ,
} ,
watch : {
} ,
computed : {
} ,
} ;
</ script>
使用gsap实现过度
< template>
< div>
< transition
@before-enter = " beforeEnter"
@enter = " enter"
@before-leave = " beforeLeave"
@leave = " leave"
>
< div class = " box" v-if = " flag" > </ div>
</ transition>
< button @click = " flag = !flag" > toggle</ button>
</ div>
</ template>
< script>
import {
School, Stu } from "./components" ;
import {
gsap } from "gsap" ;
export default {
name : "" ,
props : {
} ,
data ( ) {
return {
flag : true ,
} ;
} ,
components : {
School, Stu } ,
methods : {
beforeEnter ( el ) {
gsap. set ( el, {
duration : 3 ,
width : 0 ,
height : 0 ,
} ) ;
console. log ( 1 ) ;
} ,
enter ( el, done ) {
gsap. to ( el, {
width : 200 ,
height : 200 ,
onComplete : done,
} ) ;
console. log ( 1 ) ;
} ,
beforeLeave ( el, done ) {
gsap. set ( el, {
width : 200 ,
height : 200 ,
} ) ;
console. log ( 1 ) ;
} ,
leave ( el, done ) {
gsap. to ( el, {
width : 0 ,
height : 0 ,
onComplete : done,
} ) ;
console. log ( 1 ) ;
} ,
} ,
watch : {
} ,
computed : {
} ,
} ;
</ script>
< style>
.box {
background-color : red;
}
</ style>
(3)transition-group组件
平移属性move-class
< template>
< div>
< button @click= "random" > 打乱< / button>
< transition- group
tag= "div"
class = "wraps"
move- class = "move"
>
< div
v- for = "item in arr"
: key= "item.id"
class = "item"
>
{
{
item. number } }
< / div>
< / transition- group>
< / div>
< / template>
< script>
import {
School, Stu } from './components'
import _ from 'lodash'
export default {
name : '' ,
props : {
} ,
data ( ) {
return {
arr : [ ]
}
} ,
components : {
School, Stu } ,
mounted ( ) {
this . arr = Array . apply ( null , {
length : 81 } ) . map ( ( _, index ) => {
return {
id : index,
number : ( index % 9 ) + 1
}
} )
} ,
methods : {
random ( ) {
this . arr = _. shuffle ( this . arr)
}
} ,
watch : {
} ,
computed : {
}
}
< / script>
< style lang= "less" scoped>
. wraps {
display : flex;
flex- wrap: wrap;
width : calc ( 25px * 10 + 9px) ;
. item {
width : 25px;
height : 25px;
border : 1px solid #ccc;
text- align: center;
}
}
. move {
transition : all 1s;
}
< / style>
状态过度(数字过度颜色过度)
< template>
< div>
< h1> {
{
num. tweenedNumber. toFixed ( 0 ) } } < / h1>
< input
type= "text"
v- model= "num.current"
>
< / div>
< / template>
< script>
import {
School, Stu } from './components'
import _ from 'lodash'
import gsap from 'gsap'
export default {
name : '' ,
props : {
} ,
data ( ) {
return {
num : {
current : 0 ,
tweenedNumber : 0
}
}
} ,
components : {
School, Stu } ,
methods : {
} ,
watch : {
num : {
deep : true ,
handler ( newVal ) {
gsap. to ( this . num, {
duration : 1 ,
tweenedNumber : newVal. current
} )
}
}
} ,
computed : {
}
}
< / script>
(4)keep-alive组件
props
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
基本使用
< template>
< div>
< keep- alive : include= "['A']" >
< A v- if = "flag" > < / A >
< / keep- alive>
< button @click= "flag=!flag" > 显示/ 隐藏< / button>
< / div>
< / template>
< script>
import {
A } from './components'
export default {
props : {
} ,
data ( ) {
return {
flag : true
}
} ,
components : {
A }
}
< / script>
生命周期变化
activated ( ) {
console. log ( '组件被激活了' ) ;
} ,
deactivated ( ) {
console. log ( '组件被缓存了' ) ;
} ,
2.组件间通讯
1.props父传子
父组件传递值
< template>
< div>
< A title= "向子组件传值" > < / A >
< / div>
< / template>
< script>
import {
A , B } from './components'
export default {
components : {
A , B } ,
} ;
< / script>
< style lang= "less" > < / style>
子组件接受值
< template>
< div> A 组件< / div>
< / template>
< script>
export default {
props : {
title : {
type : String
}
} ,
mounted ( ) {
console. log ( this . title)
}
}
< / script>
2.emit子传父
父组件给子组件绑定事件
< template>
< div>
< A @getChild = " getChild" > </ A>
</ div>
</ template>
< script>
import {
A , B } from './components'
export default {
components : {
A , B } ,
methods : {
getChild ( value ) {
console. log ( value)
}
}
}
</ script>
子组件触发父组件的事件
< template>
< div @click = " $emit(' getChild' ,100)" > A组件</ div>
</ template>
(1)props和emit实现简单的双向据绑定
父组件
< template>
< div>
父组件{
{
value} }
< br>
< A : value= "value" @setValue= "setValue" > < / A >
< / div>
< / template>
< script>
import {
A , B } from './components'
export default {
components : {
A , B } ,
data ( ) {
return {
value : 1
}
} ,
methods : {
setValue ( value ) {
this . value= value
}
}
}
< / script>
子组件
< template>
< div>
子组件 :
< input
type= "text"
v- model= "modelValue"
>
< / div>
< / template>
< script>
export default {
props : {
value : {
type : Number
}
} ,
computed : {
modelValue : {
get ( ) {
return this . value
} ,
set ( value) {
this . $emit ( 'setValue' , + value)
}
}
}
}
< / script>
(2)mixin混入拆分双向数据绑定
混入属性
export const mixinModel = {
computed : {
modelValue : {
get ( ) {
return this . value
} ,
set ( value) {
this . $emit ( 'setValue' , + value)
}
}
}
}
子组件引入混入
< template>
< div>
子组件 :
< input
type= "text"
v- model= "modelValue"
>
< / div>
< / template>
< script>
import mixinModel from '../mixin'
export default {
props : {
value : {
type : Number
}
} ,
mixin : [ mixinModel]
}
< / script>
3.插槽通信
(1)默认插槽
父组件
< template>
< div>
< A > < h1> 默认插槽< / h1> < / A >
< / div>
< / template>
< script>
import {
A } from './components'
export default {
components : {
A } ,
} ;
< / script>
子组件
< template>
< div>
< ! -- 默认插槽占位 -- >
< slot> < / slot>
< / div>
< / template>
(2)具名插槽
父组件
< template>
< div>
< A >
< template #name>
< h1 > 具名插槽< / h1>
< / template>
< / A >
< / div>
< / template>
< script>
import {
A } from './components'
export default {
components : {
A }
}
< / script>
子组件
< template>
< div>
< ! -- 具名插槽占位 -- >
< slot name= "name" > < / slot>
< / div>
< / template>
(3)作用域插槽(scope传值重点)
理解:数据在子组件的自身,但根据数据生成的结构需要父组件决定。
子组件
< template>
< div>
< ! -- 作用域插槽占位,slot传的值最后会被#name= "scoped" scoped会接受list-- >
< slot name= "name" : list= "list" > < / slot>
< / div>
< / template>
< script>
export default {
data ( ) {
return {
list : [ '作' , '用' , '域' , '插' , '槽' ]
}
} ,
}
< / script>
父组件
< template>
< div>
< ! -- 作用域插槽占位,slot传的值最后会被#name= "scoped" scoped会接受list-- >
< slot name= "name" : list= "list" > < / slot>
< / div>
< / template>
< script>
export default {
data ( ) {
return {
list : [ '作' , '用' , '域' , '插' , '槽' ]
}
} ,
}
< / script>
4.全局事件总线
挂载$bus
import Vue from 'vue'
import App from './App.vue'
Vue. config. productionTip = false
new Vue ( {
render ( creatElement ) {
return creatElement ( App)
} ,
beforeCreate ( ) {
Vue . prototype. $bus= this
}
} ) . $mount ( '#app' )
A组件
< template>
< div>
A 组件
< button @click= "sendB" > 发生信息给B < / button>
< / div>
< / template>
< script>
export default {
methods : {
sendB ( ) {
this . $bus. $emit ( 'getB' , 'A组件发生信息给B组件' )
}
}
}
< / script>
B组件
< template>
< div> < / div>
< / template>
< script>
export default {
mounted ( ) {
this . $bus. $on ( 'getB' , value => {
console. log ( value)
} )
} ,
beforeDestroy ( ) {
this . $bus. $off ( 'getB' )
}
}
< / script>
(1)实现简单的发布和订阅模式
发布订阅的实现
class Bus {
list
constructor ( ) {
this . list = {
}
}
on ( name, callback ) {
const fn = this . list[ name] || [ ]
fn. push ( callback)
this . list[ name] = fn
}
emit ( name, ... args ) {
const evnentName = this . list[ name]
evnentName. forEach ( fn => {
fn . apply ( this , args)
} )
}
off ( name ) {
delete this . list[ name]
}
}
export default new Bus ( )
A组件
< template>
< div>
A 组件
< button @click= "sendB" > 发生信息给B < / button>
< / div>
< / template>
< script>
import bus from '../utils'
export default {
methods : {
sendB ( ) {
bus. emit ( 'getB' , 'A组件发生信息给B组件' )
}
}
}
< / script>
B组件
< template>
< div> < / div>
< / template>
< script>
import bus from '../utils'
export default {
mounted ( ) {
bus. on ( 'getB' , value => {
console. log ( value)
} )
} ,
beforeDestroy ( ) {
bus. off ( 'getB' )
}
}
< / script>
5.ref调用
子组件
< template>
< div>
A 组件
< / div>
< / template>
< script>
export default {
data ( ) {
return {
childVal : '父组件可以通过ref调用它'
}
} ,
methods : {
childrenFn ( ) {
console. log ( '父组件可以通过ref调用它' )
}
}
}
< / script>
父组件
< template>
< div>
< A ref= "Ac" > < / A >
< / div>
< / template>
< script>
import {
A } from './components'
export default {
props : {
} ,
components : {
A } ,
mounted ( ) {
console. log ( this . $refs. Ac. childVal)
console. log ( this . $refs. Ac. childrenFn)
}
}
< / script>
自定义的配置
1. 自定义指令
(1)局部自定义指令
基本使用
< template>
< div>
< input
type= "text"
v- focus
>
< / div>
< / template>
< script>
import {
} from './components'
export default {
directives : {
focus : {
bind ( el, binding, vnode ) {
console. log ( '指令第一次绑定到元素时' )
} ,
inserted ( el, binding, vnode ) {
el. focus ( )
console. log ( '被绑定元素插入父节点时调用' )
} ,
update ( el, binding, vnode, oldVnode ) {
console. log ( '所在组件的 VNode 更新时调用' )
} ,
componentUpdated ( el, binding, vnode ) {
console. log ( '指令所在组件的 VNode 及其子 VNode 全部更新后调用' )
} ,
unbind ( el, binding, vnode ) {
console. log ( '只调用一次,指令与元素解绑时调用' )
}
}
}
}
< / script>
自定义托拽指令的实现
< template>
< div>
< div
style= "position: absolute;
width : 100px;
height : 100px;
background- color: red; "
v- move
> < / div>
< / div>
< / template>
< script>
import {
} from './components'
export default {
data ( ) {
return {
value : 1
}
} ,
directives : {
move : {
inserted : ( el, binding, vnode ) => {
const move = e => {
console. log ( parseInt ( el. style. width) )
el. style. left = e. clientX - parseInt ( el. style. width) / 2 + 'px'
el. style. top = e. clientY - parseInt ( el. style. height) / 2 + 'px'
}
el. addEventListener ( 'mousedown' , ( ) => {
document. addEventListener ( 'mousemove' , move)
document. addEventListener ( 'mouseup' , ( ) => {
document. removeEventListener ( 'mousemove' , move)
} )
} )
}
}
}
}
< / script>
(2)全局自定义指令
入口文件中定义
import Vue from "vue" ;
import App from "./App.vue" ;
Vue. config. productionTip = false ;
Vue. directive ( 'focus' , {
inserted ( el ) {
el. focus ( )
}
} )
export const vm = new Vue ( {
render ( creatElement ) {
return creatElement ( App) ;
} ,
beforeCreate ( ) {
Vue . prototype. $A = '全局变量'
Vue . prototype. $func = ( ) => {
console. log ( '全局函数' ) ;
}
}
} ) . $mount ( "#app" ) ;
组件中使用
< template>
< div>
< input
type= "text"
v- focus= 'value'
>
< / div>
< / template>
2. 全局变量
定义全局变量
import Vue from "vue" ;
import App from "./App.vue" ;
Vue. config. productionTip = false ;
export const vm = new Vue ( {
render ( creatElement ) {
return creatElement ( App) ;
} ,
beforeCreate ( ) {
Vue . prototype. $A = '全局变量'
Vue . prototype. $func = ( ) => {
console. log ( '全局函数' ) ;
}
}
} ) . $mount ( "#app" ) ;
使用全局变量
< script>
import {
} from './components'
export default {
mounted ( ) {
console. log ( this . $A )
console. log ( this . $func)
}
}
< / script>
3. 自定义插件
(1)简单的使用
定义组件
< template>
< div v- if = "flag" >
我是自定的插件组件
< / div>
< / template>
< script>
export default {
data ( ) {
return {
flag : false
}
} ,
methods : {
show ( ) {
this . flag = true
} ,
hide ( ) {
this . flag = false
}
}
}
< / script>
挂载插件到Vue上(样式挂载到body上,方法挂载到全局)
import C from './components/C.vue'
import Vue from 'vue'
const contructor = Vue. extend ( C )
const instance = new contructor ( )
const div = document. createElement ( 'div' )
instance. $mount ( document. body. appendChild ( div) )
export default {
install ( Vue ) {
Vue . prototype. $C = {
hide : instance. hide,
show : instance. show,
}
} ,
}
入口文件中引入插件
import plugin from './plugin'
Vue. use ( plugin)
(2)封装Message提示插件
定义组件
< template>
< div
class = "xtx-message"
: style= "style[type]"
v- if = "flag"
>
< ! -- 上面绑定的是样式 -- >
< ! -- 不同提示图标会变 -- >
< i
class = "iconfont"
: class = "[style[type].icon]"
> < / i>
< span class = "text" > {
{
text } } < / span>
< / div>
< / template>
< script>
export default {
props : {
text : {
type : String,
default : ''
} ,
type : {
type : String,
default : 'warn'
}
} ,
data ( ) {
return {
style : {
warn : {
icon : 'icon-warning' ,
color : '#E6A23C' ,
backgroundColor : 'rgb(253, 246, 236)' ,
borderColor : 'rgb(250, 236, 216)'
} ,
error : {
icon : 'icon-shanchu' ,
color : '#F56C6C' ,
backgroundColor : 'rgb(254, 240, 240)' ,
borderColor : 'rgb(253, 226, 226)'
} ,
success : {
icon : 'icon-queren2' ,
color : '#67C23A' ,
backgroundColor : 'rgb(240, 249, 235)' ,
borderColor : 'rgb(225, 243, 216)'
}
} ,
flag : false
}
} ,
methods : {
show ( ) {
this . flag = true
} ,
hide ( ) {
this . flag = false
}
}
}
< / script>
< style scoped lang= "less" >
. xtx- message {
width : 300px;
height : 50px;
position : fixed;
z- index: 9999 ;
left : 50 % ;
margin- left: - 150px;
top : 25px;
line- height: 50px;
padding : 0 25px;
border : 1px solid #e4e4e4;
background : #f5f5f5;
color : #999 ;
border- radius: 4px;
i {
margin- right: 4px;
vertical- align: middle;
}
. text {
vertical- align: middle;
}
}
< / style>
挂载插件到Vue上(样式挂载到body上,方法挂载到全局)
import Message from './components/Message.vue'
import Vue from 'vue'
const MessageFn = ( message ) => {
const contructor = Vue. extend ( Message)
const instance = new contructor ( {
propsData : message} )
console. log ( instance)
instance. $mount ( document. createElement ( 'div' ) )
document. body. appendChild ( instance. $el)
const show = instance. show
const hide = instance. hide
show ( )
setTimeout ( ( ) => {
hide ( )
} , 3000 )
}
export default {
install ( Vue ) {
Vue . prototype. $Message = MessageFn
} ,
}
入口文件中引入插件
import plugin from './plugin'
Vue. use ( plugin)
使用插件
< script>
import {
} from './components'
export default {
mounted ( ) {
console. log ( this . $Message ( {
type : 'success' , text : '注册组件成功' } ) )
}
}
< / script>
移动端适配
1.第一种适配方案
安装依赖yarn add amfe-flexible postcss [email protected]
main.ts引入amfe-flexibleimport "amfe-flexible"
根目录下创建postcss.config.js文件并配置
module. exports = {
plugins : {
'postcss-pxtorem' : {
rootValue : 37.5 ,
propList : [ '*' ]
}
}
}
2.第二种适配方案
安装依赖yarn add postcss-px-to-viewport -D
vite.config.ts内置postcss.config.js
中修改配置
import {
fileURLToPath, URL } from 'node:url'
import pxtoViewPort from 'postcss-px-to-viewport'
import {
defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig ( {
plugins : [ vue ( ) ] ,
css : {
postcss : {
plugins : [
pxtoViewPort ( {
unitToConvert : 'px' ,
viewportWidth : 750 ,
unitPrecision : 6 ,
propList : [ '*' ] ,
viewportUnit : 'vw' ,
fontViewportUnit : 'vw' ,
selectorBlackList : [ 'ignore-' ] ,
minPixelValue : 1 ,
mediaQuery : true ,
replace : true ,
landscape : false
} )
]
}
} ,
resolve : {
alias : {
'@' : fileURLToPath ( new URL ( './src' , import . meta. url) )
}
}
} )
创建postcss-px-to-viewport.d.ts的声明文件
declare module 'postcss-px-to-viewport' {
type Options = {
unitToConvert : 'px' | 'rem' | 'cm' | 'em'
viewportWidth : number
viewportHeight : number
unitPrecision : number
viewportUnit : string
fontViewportUnit : string
selectorBlackList : string[ ]
propList : string[ ]
minPixelValue : number
mediaQuery : boolean
replace : boolean
landscape : boolean
landscapeUnit : string
landscapeWidth : number
}
export default function ( options : Partial< Options> ) : any
}
在tsconfig.json中引入声明文件
{
"extends" : "@vue/tsconfig/tsconfig.web.json" ,
"include" : [ "env.d.ts" , "src/**/*" , "src/**/*.vue" , "postcss-px-to-viewport.d.ts" ] ,
"compilerOptions" : {
"baseUrl" : "." ,
"types" : [ "element-plus/global" ] ,
"paths" : {
"@/*" : [ "./src/*" ]
}
} ,
"references" : [
{
"path" : "./tsconfig.config.json"
}
]
}
注意:如果外面用到了postcss.config.js
,在postcss.config.js
中添加配置文件
module. exports = {
plugins : {
tailwindcss : {
} ,
autoprefixer : {
} ,
'postcss-px-to-viewport' : {
unitToConvert : 'px' ,
viewportWidth : 320
}
}
}