事件修饰符
.self 点击自己才会触发,包括冒泡情况也会跳过
.capture 冒泡顺序倒置
绑定类名
:class="[‘classname’,flag ? ‘classname’ : ‘’,{‘classname’ : flag}]"
{‘需要绑定的类名’:是否绑定} 该对象也可以在data中声明赋值
绑定样式
:style="{color:‘red’,‘font-size’:‘16px’}"
样式的名称带-,必须用’'括起来;多个对象绑定时:style="[obj1,obj2]"
v-on绑定事件
可以写() 也可以不加 v-on=“fn” @on=“fn()”
$event 作为参数的时候传递原生的事件对象
自定义指令
第一个参数:指令的名称 第二个参数:对象
指令名称不需要"v-";指令可以在不同的生命周期阶段执行
bind:指令被绑定到元素上的时候执行
inserted:绑定指令的元素被添加到父元素上的时候调用
Vue.directive(“color”,{
bind:function (el,obj){ //第二个参数是个对象,常用obj.value获取指令绑定的值
el.style.color = =‘red’
// el.focus(); 该事件在bind阶段中不生效,元素还未被渲染,应该在inserted生命周期中执行
}
})
红色
在bind的回调函数中调用第二个obj参数的value获得blue局部指令
与methods同级
directives:{
“color”:{
bind:fucntion(el,obj){
el.style.color = obj.value;
}
}
}
计算属性
与methods同级
conputed:{
“key”:function(){
let value = ‘’;
return value;
}
}
计算属性不是函数所以调用的时候不要() 直接插值调用{{计算属性名称}}
计算属性会将返回的结果缓存起来,结果没有发生变化,就执行一次;数据常变用函数,变动少用计算属性性能高
全局过滤器
Vue.filter(‘过滤名称’,function(value){
//处理数据的函数
value = value.replace(/学院/g,“大学”)
return value;
});
使用:{{插值变量 | 过滤器名称}} 1.只能在插值语法和v-bind中使用 2.过滤器可以连续使用 {{插值变量 | 过滤器1 | 过滤器2}}
局部过滤器
只能在自定义过滤器的vue实例中使用
和methods同级
filters:{
‘过滤器名称’:function(value){
return value;
}
}
在使用过滤器的时候,可以在过滤器名称后面加上()给过滤器的函数传递参数
{{number | filt(2)}}
filters:{
‘过滤器名称’:function(被过滤的值,过滤器参数){
return value;
}
}
过渡动画
标签包围,通过css控制样式,过程中写transition:all 3s;
.v-enter 进入开始前 opacity:0;
.v-enter-active 移入开始后 transition: all 3s;
.v-enter-to 进入过程中 opacity:1;
.v-leave 离开 开始前 opacity:1;
.v-leave-active离开后 transition: all 3s;
.v-leave-to 离开 过程 opacity:0;
一个transition标签中只能放一个元素
appear刷新页面的时候执行动画
class对应的v-enter类名为 .one-enter
钩子函数:v-on:before-enter=“beforeEnter” enter after-enter before-leave
beforEnter(el){//el是当前元素} enter(el,done){//done 是否已经执行完毕,执行完毕后要调用 done(); 回调,否则afterEnter不会执行} afterEnter(el){}
通过js钩子函数实现动画,vue会查找类名;transition标签中可以通过v-bind:class=“false” 取消查找类名
如果通过js钩子函数来实现过渡动画,要在执行过程执行结束回调前执行el.offsetWidth 或 el.offsetHeight
一刷新就执行js动画,最好在过程中延迟后执行done()回调;
第三方js动画库过渡 example : Velocity
enter(el,done){
Velocity(el,{opacity:1,marginLeft:“500px”},3000)
el:元素 Object 动画的属性 Number 动画时长
}
第三方css动画库 example: animated
绑定自定义过渡类名(组件属性):enter-class(动画进入开始) enter-active-class(动画进入过程) enter-to-class(动画进入结束) leave-class leave-active-class leave-to-class
使用:
多个元素动画可用包裹,其使用和transition标签一致
for注意点
v-for在渲染元素的时候,会先查看缓存中有没有需要渲染的元素
如果缓存中没有要渲染的元素,就会创建一个新的放到缓存中,如果缓存中有要渲染的元素,就不会创建一个新的,而是直接复用原有的
在vue中,只要数据发生改变,就会重新渲染
不要用index当做key
自定义全局组件
1.创建组件构造器
模板只能有一个根元素
let Profile = Vue.extend({
template:<div>模板html内容</div>
})
2.注册已建好的组件
Vue.component(“abc”,[Profile])
第一个参数:注册组件的名称
第二个参数:构建好的组件构造器
使用:
全局组件简写
Vue.component(‘组件名称’,{这个对象就是组件构造器,不需要Vue.extend创建})
也可以将html模板写在
然后使用VUe.component(‘组件名称’,{template:"#模板id"})注册组件
在Vue中有template标签可以写html模板内容,带上id属性即可
局部组件
在当前vue实例中使用
使用与methods同级定义:
components:{
“组件名称”:{
template:"#模板id"
}
}
组件中data必须是个函数,与vue实例不太一样
data:function(){
return {
abc:“你好”
}
}
组件中的data如果不是通过函数返回,多个相同组件就会共用一份数据,导致数据混乱.
通过函数返回data的组件,每创建一个新的组件就会调用这个方法,将这个方法返回的数据和当前创建的组件绑定在一起,这样就避免了数据混乱
切换组件
与元素切换一样,v-if控制
动态组件:
与v-if的区别:v-if每次都会删掉组件再加载,而动态组件被包住后切换就不会销毁,从缓存中取.
给组件添加动画:单个组件添加到标签中即可;多个组件添加到中即可
组件切换时动画是同时进行,则可以切换动画模式: 1.in-out:新元素进行过渡完成后当前再进行过渡离开; 2.当前元素先进行过渡,完成后新元素过渡进入;
过渡模式使用:
父子组件
Vue.Component(“father”,{
template:"#father",
components:{
“son”:{
template:"#son"
}
}
})
父组件中调用了子组件,子组件在父组件中注册,只能在父组件调用;
子组件访问父组件数据要通过 v-bind:自定义接收名称=“传递数据” ; 子组件通过props:[“自定义接收名称”] 接收数据
子组件使用{{自定义接收名称}} ; 接收名称不能用驼峰命名,最好小写字母;若使用的时候要驼峰命名使用,接收名称需要在大写字母前面加- 并且大写改为小写; 如: 使用: props[“parentName”] 插值{{parentName}}
组件命名注意:注册的时候使用驼峰命名,使用的时候是不能使用驼峰命名的,大写字母前面要使用- ;
例如:Vue.component(“myFather”,{template:"#father"})使用
传递方法的时候也是不能使用驼峰命名的 <son @parent-say=“say”> 子组件中调用父组件方法:this.emit(“parent-say”) 用了横杠也不能使用驼峰命名调用,只能横杠调用
父组件传递子组件方法 v-on:自定义接收名称=“要传递的方法” ;或者 @自定义接收名称=“要传递的方法”
使用与传递属性不同,不需要在子组件props中接收;需要在子组件中自定义一个方法;使用this.$emit(“自定义接收名称”)
子组件传递给父组件传递参数:
在父组件中定义方法,传递给子组件;然后在子组件调用父组件方法,通过传递参数的方式设置父组件的数据
this.$emit(‘自定义方法名称’,参数1,参数2)
多级传递:需要一级一级往下传递
爷爷组件中调用爸爸组件 爸爸组件中pros[‘gfvalue’]接收;{{gfvalue}}使用;传递给儿子组件类似 再在儿子组件中pros[“fvalue”] 接收后{{fvalue}}使用
方法的传递也是一级一级传递 <father @gffun=“gfFun”> 爸爸组件中调用 自己在methods里面创建方法fFun(){this.emit(“gffun”)} ; 然后在爸爸组件中传递给儿子组件 <son @ffun=“fFun”> 儿子组件使用在methods中创建方法 sonFun(){this.emit(“ffun”)} 使用到爷爷组件中的方法
匿名插槽:
想在子组件的时候,给子组件动态添加内容就需要使用插槽
组件的模板中使用slot标签就是插槽,插槽其实就是一个坑,只要有了这个坑,就可以根据需要填坑
默认数据
插槽可以指定默认数据,如果没有填坑就显示这个默认数据,填了坑就使用填坑的数据
注意:插槽是可以指定名称的,默认情况没有指定名称,称为 匿名插槽
匿名插槽特点:有多少个匿名插槽,填充数据就会被拷贝多少份.推荐只使用一个匿名插槽
具名插槽:
想在组件中填充不同的内容就可以使用具名插槽
可以在定义插槽的时候给插槽添加一个name属性,通过这个name属性来指定插槽的名称;若没有通过slot属性告诉Vue,当前的内容是不知道要填充到哪个插槽中,则不会填充.
在组件的模板中使用
<template>
<slot name="one">具名插槽1默认内容</slot>
<slot name="two">默认内容2</slot>
</template>
在使用组件时
<son>
<div slot="one">指定插槽内容1</div>
<div slot="two">指定插槽内容2</div>
</son>
v-slot标签
v-slot指令只能使用在template标签上
<son>
<template v-slot:one>
<div>我是插槽one的内容1</div>
<div>我是插槽one的内容2</div>
</template>
<template v-slot:two>
<div>我是插槽two的内容1</div>
</template>
</son>
指定具名插槽的名称进行插槽填充
v-slot的简写形式 #one
<son>
<template #one>
<div>插槽one的内容</div>
</template>
</son>
VueX
虽然通过借助父组件能够实现兄弟组件之间的数据传递,但这种方式非常的复杂,;则可以使用VueX
使用
1.导入Vuex.js前先导入Vue.js
2.创建Vuex对象
const store = new Vuex.Store({
<!-- state相当于组件中的data,专门用于保存共享数据的 -->
state:{
msg:'共享数据'
}
})
3.使用:在祖先组件中和template同级添加key store:store, 必须通过this.$store.state.msg 调用
4.只要祖先组件中保存了Vuex对象,祖先组件和所有的后代都可以使用Vuex中保存的共享数据了
修改共享数据:this.$store.state.共享数据变量名称 = 值;
但是!VueX不推荐直接赋值修改,数据错误不好排查;使用mutations
const store = new Vuex.Store({
state:{
共享数据:"值"
},
mutations:{ //用于保存修改共享数据的方法
mAdd(state){ //自动传递一个state参数,state中保存了共享数据
state.共享数据 = state.共享数据 + 1; //内部对共享数据进行操作
},
}
})
修改共享数据方法使用:this.$store.commit(“mAdd”) 进行调用
Vuex - getters属性
与computed计算属性类似,将返回结果缓存起来
const store = new Vuex.Store({
state:{
msg:“你好”,
},
mutations:{},
getters:{
format(state){
console.log(“返回值一样只执行一次”)
return state.msg + “东东”;
}
},
})
页面中使用: 先引入vuex store:store, {{this.$store.getters.format}}
Vue Router
和v-if 和 v-show一样用来切换组件显示的;Vue Router用哈希来切换(#/xxx)
比v-if和v-show强大的是还能在切换的时候传递参数
Vue Router使用
-
导入Vue Router(需先导入Vue)
-
定义切换的规则
const one = { //组件1 template:'#one' }; const two = { //组件2 template:'#two' }; const routers=[ //设置根目录访问时,默认重定向到/one {path:'/',redirect:'/one'}, <!--数组中每个对象就是一个规则--> {path:'/one',component:one}, {path:'/two',component:two}, ]
-
根据自定义的切换规则创建路由对象
const router = new VueRouter({ routes:touters })
-
将创建好的路由对象绑定到Vue的实例上
let vue = new Vue({ el:"#app", router:router, })
-
界面中的使用
<div id="app">
<a href="#/one">切换到第一个页面</a>
<a href="#/two">切换到第二个页面</a>
<!--路由出口-->
<!--将匹配到的组件渲染到这-->
<router-view></router-view>
</div>
通过router-link设置hash标签
比a标签好:兼容性好,ie9降级使用hash模式还是html5的history模式和hash模式切换不需要做任何变动;
如果使用router-link设置url的hash值,不需要#,使用to属性来控制hash值
<div id="app">
<router-link to="/one">切换到第一个界面</router-link>
<router-link to="/two" tag="button">切换到第二个界面</router-link>
</div>
默认情况下Vue在渲染router-link的时候,是通过a标签来渲染的;
如果不想使用a标签来渲染,可以通过tag属性来告诉vue通过什么标签来渲染
.router-link-active{这个类名是重写当前激活的router-link的标签样式};
也可以通过linkActiveClass自定义激活时的class样式类名,会替换router-link-active类名
const router = new VueRouter({
routes:routes,
linkActiveClass:'custom-active'
})
Vue Router传递参数
1.通过url参数的方式传递
<router-link to="/one?name=ok&age=2"></router-link>
可在one的组件的生命周期方法中通过 this. r o u t e . q u e r y . n a m e 和 t h i s . route.query.name 和 this. route.query.name和this.route.query.age 获得参数值
2.通过指定路由规则的方式传参
//指定路由该位置的对应参数接收
const routes = [
{path:'/one/:name/:age',component: one}
]
传递zhangsan到对应的name 22到对应的age参数
<route-link to="/one/zhangsan/22"></route-link>
嵌套路由
<template id="one">
<div>
<p>one组件</p>
<router-link to="/one/onesub1">子组件1界面</router-link>
<router-link to="/one/onesub2">子组件2界面</router-link>
<!--匹配到的路由渲染到这里-->
<router-view></router-view>
</div>
</template>
<template id="onesub1">
<div>子组件1界面</div>
</template>
<template id="onesub2">
<div>子组件2界面</div>
</template>
1.定义组件
const onesub1 = {
template:'#onesub1'
}
const onesub2 = {
template:'#onesub2'
}
const one = {
template:'#one',
component:{
onesub1:onesub1,
onesub2:onesub2
}
}
2.定义切换路由规则
如果是嵌套路由的子路由,不用再写一级路由的地址,也不用斜杠
const routes = [
{
path:'/one',
component:one,
children:[
{
//one下面嵌套的子路由
path:'onesub1',
component:onesub1
},
{
paht:'onesub2',
component:onesub2
}
]
},
//以下方式不会进行嵌套,会直接覆盖页面
//{path:'/one/onesub1',component:onesub1},
//{path:'/one/onesub2',component:onesub2}
]
命名视图
和匿名插槽一样,如果指定了多个标签,多个标签内的内容是一样的.
const routes = [
{
path:'/',
components:{
key: value,
name1:one,
nam2,two
}
}
]
使用
<router-view name="name1" ></router-view>
<router-view name="name2" ></router-view>
这样就可以显示不同的组件
watch属性
watch属性属于vue实例对象
let vue = new Vue({
el:'#app',
data:{
num1:0,
},
watch:{
//要监听的属性名称
num1:function(newValue,oldValue){
console.log("属性变更值",newValue);
console.log("属性变更前的值",oldValue);
}
}
})
使用:监听路由
vue.$route.path 当前路由地址
watch:{
"$route.path":function(newval,oldval){
console.log("切换路由后地址",newval)
console.log("切换路由前地址",oldval)
}
}
生命周期
创建阶段
beforeCreated:还未初始化data和methods方法
created:此时已初始化了data和methods,此时还没有编译模板
beforeMount:根据data中的数据生成HTML,但是还没有挂载到页面上
mounted:data中的数据已挂载到页面
运行阶段
beforeUpdate:
该生命周期被调用时,表示Vue实例中保存的数据被修改了;
只有保存的数据被修改了才会调用beforeUpdate,否则不会调用
调用时数据已经更新了,页面还未渲染更新
updated:数据与页面都已更新后调用此生命周期函数
销毁阶段
Vue生命周期方法在组件中也可以使用,使用v-if切换组件可使组件销毁与创建
beforeDestroy: 当前组件即将销毁了;只要组件不被销毁,beforeDestroy就不会被处触发;此生命周期是最后能访问到data数据和方法的函数
destroyed:当前组件已经被销毁了,不要在此生命周期函数中操作数据与方法了.
Vue特殊特性
ref
想要拿到DOM元素,可以通过ref来获取;
Vue并不推荐使用原生操作DOM,如:
document.querySelector('p')
this.$refs 获取
<p ref='mypp'>p元素</p>
this.$refs.mypp; //获取mypp元素
Vue组件渲染方式
<div id="app">
<!-- <one></one> 未使用render渲染,则在#app的控制区域中-->
</div>
<template id="one">
<div>
我是组件1
</div>
</template>
<script>
Vue.component("one",{
template:"#one"
});
let vue = new Vue({
el:'#app',
render:function(createElement){
let html = createElement("one"); //将组件名称传入,此时返回组件的元素就不在控制区域#app中
return html;
}
})
</script>
Vue CLI
node环境中 安装
npm install -g @vue/cli
创建项目
vue create project-name
查看版本
vue --version
打包运行
根据package.json文件内 scripts 内的serve属性可知
npm run serve
进行启动运行
打包
npm run build
多一个dist的打包文件夹
文件结构
Vue-CLI2.x 版本是有build文件夹和config 文件夹;里面存储了webpack的相关配置
Vue-CLI3之后没有build和config文件夹
node_modules:存储了相关的依赖包
public:静态资源,不会经过webpack,要用绝对路径来引用它们,一般存永不变的静态资源或webpack不支持的第三方库
src:代码文件夹
assets:项目中自己的一些静态文件(图片/字体)
component:自定义组件(小组件)
views:自定义组件(页面级大组件)
router:存储VueRouter相关文件
store:存储Vuex相关文件
App.vue:根组件
main.js :入口
Vue-CLI中使用VueX 与vue-router
src - store目录中 index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
main.js中
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
APP.vue
<template>
<div id="app">
{{ msg }}
<button @click="getName">获取vueX的NAME</button>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
<!-- <One></One> -->
</div>
</template>
<script>
// import One from './components/one.vue'
export default {
name: "App",
data: function () {
return {
msg: "你好",
};
},
methods:{
getName(){
console.log(this.$store.state.NAME)
}
},
components:{
// One:One
}
};
</script>
<style lang="scss">
</style>
配置Vue-CLI的webpack配置
Vue-CLI对webpack原有的属性进行了一层封装
如在vue.config.js中
const webpack = require('webpack')
module.exports={
lintOnSave:false,//取消eslint校验
outputDir:'bundle',// 修改打包输出目录
configureWebpack:{
// 原生的配webpack配置
plugins:[
new webpack.BannerPlugin({
banner: 'Kid' //打包文件加印记
})
]
}
}
如果封装的webpack属性不能满足需求可以通过configureWebpack使用原生的webpack配置
elementUI
安装 npm方式
npm install element-ui -s
在main.js中 引入 并使用
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
即可在页面中使用饿了么UI组件库
<template>
<div>
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
</el-row>
</div>
</template>
elementUI 优化
按需导入,按需打包;首先,安装 babel-plugin-component:
npm install babel-plugin-component -D
修改babel.config.js
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
main.js中 按需使用
import { Button, Select } from 'element-ui';
Vue.use(Button);
Vue.use(Select);
mint UI (elementUI的移动端组件库)
npm安装
npm i mint-ui -s
main.js 完整引入
import MinUI from 'mint-ui'
import 'mint-ui/lib/style.css'
Vue.use(MintUI)
此组件库按需引入与elementui不相同
import {Button} from 'mint-ui'
import 'mint-ui/lib/style.css'
Vue.component(Button.name,Button);
Vue-Plugin
Vue.use使用插件;如果想通过此方向来注册组件,需先将组件封装成插件
如果将一个组件封装成一个插件,必须提供一个install方法;那么必须在install方法中注册当前组件
如:在src下的plugin文件夹下创建组件文件夹Loading,内有Loading.vue组件文件和index.js文件
index.js
import Vue from 'vue'
import Loading from './Loading'
export default{
install:function(){
Vue.component(Loading.name,Loading)
}
}
在main.js
import Loading from './plugin/Loading/Loading'
Vue.use(Loading);
以上可以在页面中通过使用
我们可以不使用组件调用的方式使用:
src/plugin/loading/index.js
import vue from 'vue'
import Loading from './Loading'
export default{
install:function(){
//1.根据我们的组件生成一个构造函数
let LoadingContructor = Vue.extend(Loading);
//2.根据构造函数创建实例对象
let LoadingInstance = new LoadingConstructor();
//3.随便创建一个标签(元素)
let oDiv = document.createElement('div');
//4.将创建好的标签添加到界面上
document.body.appendChild(oDIv)
//5.将创建好的实例对象挂载到创建好的元素上
LoadingInstance.$mount(oDiv)
//添加全局方法
Vue.showLoading = function(){
LoadingInstance.isShow = true;
}
/*
在页面中可以通过Vue.showLoading()调用
*/
//添加实例方法
Vue.prototype.$showLoading = function(){
LoadingInstance.show = true;
}
/*
在页面中可以通过this.$shhowLading() 使用
*/
}
}
Vue.use有第二个参数:1:注册插件2:可选对象
Vue.use(Loading,{
title:"加载中"
})
插件中的install函数可以接收两个参数
install(Vue,options){
//options传入的对象
LoadingInstance.title = options.title//就可以根据参数赋值到组件中
}