{{ 属性、表达式 }}
数据绑定和响应式
1、正常的数据类型都可以绑定并显示:数组、对象、字符串、布尔
2、特殊的 null undefined 只能绑定不能显示
3、数据变,页面也会变
1、条件渲染 控制一个元素的显示或者隐藏
v-show 通过控制样式 display:none,元素存在
v-if、v-else-if、v-else 通过控制元素节点的创建和销毁
2、事件绑定
v-on:事件名=函数
简写 @事件名=函数
注意
1、事件的处理函数写在实例的配置项 motheds
2、处理函数的默认参数是事件对象e
3、如果需要传递其他参数 事件对象需要通过 $event 手动传递
3、属性绑定
v-bind:属性名=属性值
简写 :属性名=属性值
注意 属性值是变量或者表达式
4、列表渲染
v-for 绑定一个标签 循环一个数据源
<li v-for =‘循环数据的每一项 in/of 要循环的数据‘></li>
<li v-for =‘(循环数据的每一项,每一项的下标)in/of 要循环的数据‘></li>
<li v-for="(对象value,对象里的key,下标) in 要循环的对象">{{key}}:{{value}}-{{index}}</li>
5、双向数据绑定
v-model
可以绑定一个表单元素的value 修改表单元素的 value值
data里的数据也会发生改变
注意
1、所有的表单元素都能用
2、组件也可用
6、其他指令
v-html
v-text
7、自定义指令
使用自定义指令的时候 v-指令名
全局定义,全局使用
Vue.directive(‘指令名‘,配置项)
Vue.directive(‘指令的名字‘,{
insterted(el){
el 自定义指令绑定的元素
}
})
局部定义,局部使用
在组件里定义directives:{“指令名”:{配置项}}
directives:{
‘focus‘:{
inserted(el){
el.focus()
}
}
}
指令的生命周期
1、bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
2、inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
3、update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
4、componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
5、unbind:只调用一次,指令与元素解绑时调用。
一、组件的定义
1、全局组件
定义 Vue.component(‘组件名‘,{ 组件的配置项})
2、局部组件
定义 局部组件注册在 组件里的配置项 components里
components:{
组件名:{
配置项
}
二、组件的配置项
配置项1、template(组件模板)
和实例里的 el 类似 关联dom元素
1. dom结构简单 直接使用字符串
2. dom复杂 template标签 该标签不会真正的渲染 值允许有一个根元素
1、{template:"<h1>这里是局部组件hehe</h1>"}
2、
<!-- 组件模板 -->
<template id=‘tp1‘>
<div>
<p v-for=‘item in 10‘>{{item}}</p>
</div>
</template>
Vue.component(‘hehe‘,{
template:‘#tp1‘
})
配置项2、data(状态)
组件正常情况下无法直接使用实例的数据 只能使用自己的数据
实例里的data 是一个对象
组件里的data是一个函数 返回一个对象返回的对象就是我们的数据
为了保证每一个组件有单独的左右域
data(){
return{ name:‘韩梅梅‘}
}
配置项3、methods(方法)
methods: {
add(){
// 组件里的this指向组件对象
this.num++
}
},
配置项4、filter(过滤器)
作用 对数据的处理
插值 {{要过滤的数据 |(管道符号) 过滤器的名字}}
定义全局过滤器
Vue.filter(‘过滤器的名字‘,(要过滤的数据,参数params=‘.‘)=>{
// 对数据做处理
console.log(‘需要过滤的数据‘,data)
let y= (new Date(data)).getFullYear()
let m= (new Date(data)).getMonth()+1
let d= (new Date(data)).getDate()
// 一定要返回
return `${y}${params}${m}${params}${d}`
})
定义局部过滤器
filters:{
‘过滤器名字‘:(要过滤的数据,参数(可选))=>{
return ‘理发店‘
}
}
配置项5、watch(监听)
监听数据的改变
有2个参数 一个是更新前的值 一个更新之后的值
watch监听触发的时候 dom 还没有更新
所以 数据 是更改之后的
但是 dom 是更改之前的
watch: {
num(newValue,oldValue){
console.log(‘num你变了‘)
console.log(‘new‘,newValue)
console.log(‘old‘,oldValue)
console.log(‘p‘,document.getElementById(‘p‘)) //假的
console.log(‘p‘,document.getElementById(‘p‘).innerText) //真的
},
name(){
console.log(‘改名‘)
}
},
配置项6、computed(计算属性)
1、对数据做处理,返回处理过之后的数据
2、里面定义类似方法,数据改变才会执行(缓存性)
插值 {{hehe}}
computed: {
hehe(){
console.log(‘计算属性执行了‘)
return ((this.num*2+4)-6*2/24)/8
}
},
1、父-子通信
自定义属性+props 将父亲的数据传给儿子
父组件通过自定义属性把数据给子组件,子组件用props接收
1.在子组件标签上使用自定义属性
<!-- 在tp1组件标签上使用 xixi自定义属性 -->
<tp1 :xixi=‘money‘></tp1>
2.在子组件内部通过props来接受自定义属性
两种写法
props:{
xixi:{type:Number} //传值的同时检查数据的类型
}
props:[‘xixi‘] //接收自定义属性
3.接受完了 既可以在组件里直接使用 只能用不能改
{{xixi}}
2、子-父通信
自定义事件+$emit 子组件触发父组件的方法
父组件把方法通过自定义事件给子组件,子组件再通过$emit触发自定义事件
1.在子组件标签绑定一个自定义事件、注册父组件的方法
<son @custom=‘add‘></son>
2.在子组件的内部 通过$emit 触发这个自定义事件
在子组件里注册事件,事件里$emit 触发这个自定义事件
<button @click=‘buy‘>buybuybuy</button>
methods: {
buy(){
console.log(‘我想买玩具‘)
this.$emit(‘xixi‘,3)
}
},
3、兄弟通信
a、状态提升
props和$emit的结合(子组件-同一个父组件-另一个子)
b、事件总线(bus)
1. 创建一个vue空实例 作为桥梁
let vue = new Vue()
2. 通过 $on 在空实例上注册事件
vue.$on(‘hehe‘,this.toggle) 监听hehe
3. 在任何地方 只要能获取到空实例 那就可以通过 $emit 方法触发事件
vue.$emit(‘hehe‘) 触发hehe
c、全局状态管理(vuex)
4、获取dom元素
1、通过ref绑定一个dom元素
<p id=‘hehe‘>呵呵</p>
2、通过 this.$refs 获取绑定的dom 元素
this.$refs.hehe
一、slot(插槽)
1.组件标签中的内容不会被渲染
2. slot 相当于开启一段空间来存放组件标签中的内容
3. 具名插槽
组件标签中的标签用slot属性
组件模板中的slot用name属性
两者一一对应
匿名插槽 <slot></slot>
具名插槽
<div id="app">
<hehe>
<span slot=‘top‘>我想在上面</span>
<p slot="bottom">我想在下面</p>
</hehe>
</div>
<template id="hehe">
<div class=‘test‘>
<slot name=‘top‘></slot>
<slot name=‘bottom‘></slot>
</div>
</template>
二、$nextTick
根本原因 dom的更新是异步的
数据发生改变 先改变的是虚拟dom 再去修改真实dom 这个过程是一个异步的,而组件的初始化要在dom更新完之后执行
// 上一次数据修改 导致dom更新结束之后再执行内部的回调
this.$nextTick(()=>{
this.initBanner()
})
4(4个阶段-创建-挂载-更新-销毁)
8(每个阶段2个钩子函数、一前一后)
2(缓存的钩子、keep-alive组件)
1(捕获错误的钩子函数、errorCaptured)
一、创建前后(创建虚拟dom)
beforeCreate() {
// 创建之前 没有初始化数据 没有真实dom 基本不用
console.log(‘创建之前‘)
console.log(‘this‘,this)
console.log(‘data‘,this.num)
console.log(‘dom‘,this.$refs[‘p‘])
},
created(){
//创建之后 有数据 没有真实dom
// 可以修改数据 在这里修改数据不会触发运行中的更新的生命周期
// 可以网络请求
console.log(‘创建结束‘)
console.log(‘this‘,this)
console.log(‘data‘,this.num)
this.num=5
console.log(‘dom‘,this.$refs[‘p‘])
}
二、挂载前后(虚拟dom 变成 真实dom)
beforeMount() {
// 挂载之前和created类似 有数据 可以改数据 没有dom
// 可以做网络请求
console.log(‘挂载之前‘)
console.log(‘this‘,this)
console.log(‘data‘,this.num)
console.log(‘dom‘,this.$refs[‘p‘])
},
mounted(){
//挂载结束 有数据 有dom
// 可以修改数据 可以修改dom
// 初始化的操作 swiper
console.log(‘挂载结束‘)
console.log(‘this‘,this)
console.log(‘data‘,this.num)
this.num=5
console.log(‘dom‘,this.$refs[‘p‘])
}
三、更新前后(数据被修改、dom更新)
beforeUpdate() {
// 挂载之后数据更新的时候触发,挂载之前数据跟新不会触发
// 数据 是更新之后的
// dom 是更新之前的
console.log(‘更新之前‘)
console.log(‘this‘,this)
console.log(‘data‘,this.num)
console.log(‘dom‘, this.$refs.p.innerHTML)
},
updated() {
// 数据与dom都跟新完了触发
// 数据 是更新之后的
// dom 是更新之后的
// 注意做数据的修改操作 可能引起死循环
console.log(‘更新之前‘)
this.num=Math.random()
console.log(‘this‘,this)
console.log(‘data‘,this.num)
console.log(‘dom‘, this.$refs.p.innerHTML)
},
四、销毁前后(销毁dom)
beforeDestroy() {
// 有数据 有this 也都没用
// 有dom
console.log(‘销毁之前‘)
console.log(this)
console.log(this.num)
console.log(this.$refs[‘p‘].innerHTML)
},
destroyed() {
// 有数据 有this 但是没有用
// 没有dom
console.log(‘销毁之后‘)
console.log(this)
console.log(this.num)
console.log(this.$refs[‘p‘].innerHTML)
}
注意:常用的钩子函数
1、created 网络请求
2、mounted 网络请求 初始化dom
3、destroyed 组件销毁前,解除事件绑定
全局安装
npm install -g @vue/cli
创建一个项目
vue create myapp
模块
1、Babel 把ES6+转成ES5(推荐安装)
2、TypeScript JS的超集语言
3、PWA 渐进式WEB应用
4、Router 路由(推荐安装)
5、Vuex 全局状态管理(推荐安装)
6、CSS Pre-processors sass、less(推荐安装)
7、Linter/Formatter 代码格式化(推荐安装)
8、Unit Testing 测试用的
9、E2E Testing 测试用的
选择
1、Lint and fix on commit 自动修复
2、In dedicated config files 分开配置文件
命令
npm run serve 启动
npm run build 打包
npm run lint 格式化
一、is 属性
<div is = ‘hehe‘></div>
is 可以指定渲染的组件名
div 渲染成一个叫呵呵的组件
推荐与component 标签一起使用
语法
<component is=‘组件名‘/> :is=“变量”
一、基本使用
1、配置路由文件
router文件夹下的index.js
import Vue from ‘vue‘
import VueRouter from ‘vue-router‘ // 引入vue路由模块
import Home from ‘../views/Home.vue‘ // 引入组件
Vue.use(VueRouter) // 使用路由
const routes = [
{
path: ‘/‘, // 路径
name: ‘Home‘, // 命名路由
component: Home // 组件
}
]
const router = new VueRouter({
mode: ‘history‘, // 路由模式 hash/history
// base: process.env.BASE_URL, // 应用的基路径。如果整个单页应用服务在 /app/ 下,然后 base 就应该设为 "/app/"。
routes
})
export default router
2、在main.js中注册
3、声明式导航(命名路由、命名视图、重定向)
<router-link></router-link> 跳转
属性
1、to=“路径” 路由链接
2、tag=“标签名” 渲染为此标签
3、active-class=“样式” 链接激活时使用的 CSS 类名
写法
普通
<router-link to=‘/son2‘ active-class=‘hehe‘ tag=‘span‘>son2</router-link>
to的配置项(可以根据name命名路由来跳转)
1、<router-link :to="{path:‘/recommend‘}" active-class=‘hehe‘ tag=‘span‘>推荐</router-link>
2、<router-link :to="{name:‘hehe‘}" active-class=‘hehe‘ tag=‘span‘>推荐</router-link>
<router-view></router-view> 视图
<!-- 命名视图 给视图起一个名字 -->
<router-view></router-view>
<router-view name=‘a‘></router-view>
<router-view name=‘b‘></router-view>
路由设置
{
path:‘/namerouter‘,
name:‘namerouter‘, // 命名视图
components:{
default:son1,
a:son2,
b:recommend
}
},
重定向
{
path:‘/‘,
redirect:‘/son1‘ //如果路径是地址栏路径是 / 跳转到 /son1
}
4、路由的模式 mode
通过路由表里 mode 设置
hash 路由 地址栏中有#
history 路由 没有# 和正常使用的类似
二、编程式导航
通过路由对象下的api 进行切换叫做编程式导航
vm.$router push replace go back forward
push 会将组件加入到缓存栈 可以一级一级返回
replace 没有加入缓存栈 回到最初的起点
例如
this.$router.push({path:path})
this.$router.push({name:‘起的名字‘})
this.$router.replace(path)
三、路由传参
1、动态路由
路由的路径中的有1项或者几项是变量可以变化
在目标组件 通过 $route.params 来接受数据
routes:[
{
path:‘/login/:hehe/:xixi‘
}
]
2、query传参
相当于get 传递参数 数据会出现在地址栏上 缺少安全性 有数据长度限制
this.$router.push(‘/name?us=123$ps=123‘)
this.$router.push({path:‘/name‘,query:{us:123,ps:123}})
在目标组件里通过this.$route.query()进行接受
3、params传参
不会出现在地址栏上 没有长度限制问题
不能和path一起使用
this.$router.push({name:"hehe",params:{us:123,ps:123}})
在目标组件里通过 this.$route.param()接受
四、嵌套路由 (子路由)
1. 路由表形成嵌套 子路由路径不加/
{
path:‘/my‘,
component:My,
children:[
{
path:‘userinfo‘, // "/" 表示的是根路径 在子路由写路径不加第一个/
component:UserInfo
},
{
path:‘userlogin‘,
component:UserLogin
}
]
},
2. 在目标组件里 在嵌套一个router-view
<template>
<div >
<H4>这里是my组件</H4>
<!-- 显示的是my组件下的二级路由 -->
<router-view></router-view>
</div>
</template>
五、路由拦截(某些页面登录之后才能访问 没有登录不等访问)
1、全局前置守卫 所有的路由切换都会触发
router.beforeEach((to, from, next) => {
console.log(‘from‘,from)
console.log("to",to)
let islogin = false
if(to.path===‘/singer‘){
if(islogin){
next()
}else{
next(‘/my/userlogin‘)
}
}else{
next()
}
})
2、全局后置守卫 跳转完成之后触发(基本不用)
router.afterEach((to, from) => {
console.log(‘from‘,from)
console.log("to",to)
})
3、路由独享守卫
beforeEnter: (to, from, next) => {
//路由独享守卫
console.log(‘歌手守卫‘)
next()
}
1. 多组件共享状态 多个组件使用同一个数据
2. 任何一个组件发生改变 其他的组件也要跟着发生相应的变化
一、基本使用
1. 创建全局状态管理的实例
在store的index.js里
import Vuex from ‘vuex‘
Vue.use(Vuex)
let store = new Vuex.Store({
state:{}
mutations:{}
})
export default store
2. 注册
在main.js里
import store from ‘./store/index‘
new Vue({
store,
render: h => h(App),
}).$mount(‘#app‘)
3. 在组件里使用全局状态值
a.获取渲染全局状态值
b.修改全局状态值
二、五大核心
state 全局状态数据
mutation 规定只有mutation才能修改state 通过commit方法触发
action 可以放异步操作 触发mutation 通过dispatch 触发
getter vuex里的计算属性 和state值进行关联 state发生改变
可以重新计算,并且可以在页面上直接使用
modules 模块化
三、语法
#### 简单版
1. 组件里通过 $store.state 获取全局状态数据进行渲染
2. 通过 $store.commit 方法触发mutation 修改全局状态值 整个页面都会变
let store = new Vuex.Store({
//全局状态值 所有组件都可以用
state:{
name:‘韩梅梅‘,
age:16
},
// 修改全局状态值
mutations:{
changeName(state,params){
// 修改state里的数据
state.name = params.name
},
changeAge(state,params){
state.age = params.age
}
},
// vuex里的computed
getters:{
double(state){
return state.age*2
}
},
//触发mutation
actions:{
changeAgeAction({commit} ,params){
// 通过commit函数触发mutation
函数的第一个参数默认是 context 里面有commit属性,用了解构
// let {commit} = context
commit(‘changeAge‘,params)
}
}
})
在组件里
1、this.$store.state.name 获取数据
2、this.$store.getters.double 获取计算属性
3、change(){
// dispatch 用来触发acition里的函数
this.$store.dispatch(‘changeAgeAction‘,{age:777})
}
4、change(){
// 通过commit方法触发mutation
// 参数1 要触发的方法名
// 参数2 是要传递的数据
this.$store.commit(‘changeName‘,{name:123,pass:456})
}
#### 复杂版(state-action(dispatch)-mutation(commit))
1. 组件里通过 $store.state 获取全局状态数据进行渲染
2. 通过 $store.dispatch方法 触发action里的方法
change(){
this.$store.dispatch(‘changeNameAction‘,{name:‘贞子‘})
}
3. action 触发mutation进行修改全局状态值
mutations:{
changeName(state,params){
state.name=params.name
}
},
actions:{
changeNameAction({commit},params){
// 网络请求
setTimeout(()=>{
commit(‘changeName‘,params)
},1000)
}
},
#### 辅助函数(对组件里this.$store的简写)
使用之前要引入 import { mapMutations } from ‘vuex‘
1、值类型向计算属性映射
mapState 将全局状态管理的state值映射到使用组价的计算属性
mapGetters 将全局状态管理的getters值映射到使用组价的计算属性
computed:{
...mapState([‘name‘,‘age‘,‘sex‘]),
...mapGetters([‘double‘])
},
2、函数类型向methods进行映射
mapMutations 将mutation的值映射到 方法里
mapActions 将actions里的值映射到方法
methods:{
...mapActions([‘changeNameAction‘]),
...mapMutations([‘changeName‘]),、
}
注意
辅助函数传参时,对象可以改名数组不能改名,而且只有state改名时 传一个函数
1、...mapState([‘name‘]) 名字是name
2、...mapState({hehe:state=>state.name}) 名字是hehe
3、...mapGetters({xixi:‘double‘}) 名字是xixi
4、...mapMutations({heihei:‘changeName‘}) 名字是heihei
#### 模块化版
1. 模块化之后state的取值需要添加一级模块名 其他的三个核心不变
2. 可以在模块里添加命名空间 namespaced: true,
作用就是在 mutations getters actions的名字前面 添加模块名,防止名字冲突
modules:{
// 呵呵模块
hehe:{
namespaced:true, //开启命名空间
state:{name:‘韩梅梅‘},
mutations:{
changeName(state){
state.name=‘李雷雷‘
}
},
getters:{},
actions:{}
},
// 嘻嘻模块
xixi:{
state:{age:16},
mutations:{
changeAge(state){
state.age=99
}
},
actions:{},
getters:{}
}
}
注意
1、使用modules模块化,不开namespaced,只有state加模块名
...mapState({list:state=>state.todolist.list}),
2、使用modules模块化,开了namespaced,四个都加模块名
...mapGetters({showlist:‘todolist/showList‘})
...mapMutations([‘todolist/delList‘])
一、vue内置的过渡动画(transition)
在某一个元素或者多个元素进入或者离开页面 添加动画
1.在该元素的外部添加 transition 标签
2.多个元素添加 transition-group 每一个子元素需要key
3.通过name属性添加名字
<transition-group name=‘hehe‘>
<div key = 1 class=‘test2‘ v-if=‘show‘></div>
<div key = 2 class=‘test1‘ v-if=‘show‘></div>
</transition-group>
4.在样式里添加过度样式
5. 进入 name-enter name-enter-to name-enter-active
6. 离开 name-leave name-leave-to name-leave-active
.hehe-enter{
opacity: 0;
}
.hehe-enter-to{
opacity: 1;
}
.hehe-enter-active{
transition: all 3s;
}
.hehe-leave{
opacity: 1;
}
.hehe-leave-to{
opacity: 0;
}
.hehe-leave-active{
transition: all 3s;
}
二、第三方动画库的使用(animate.css)
1. 下载安装引入 animate.css
npm install animate.css
2. 在目标元素外部添加 过渡标签(结合transition一起使用)
3. enter-active-class leave-active-class 进入离开使用的动画
<transition
enter-active-class=‘bounceInDown animated‘
leave-active-class=‘slideOutRight animated‘
>
<div key = 1 class=‘test2‘ v-if=‘show‘></div>
</transition>
注意
1、bounceInDown、slideOutRight 动画类名
2、animated 基础类名
### keep-alive 只有在vue中可以用
缓存页面
在需要缓存的组件外部 加上keep-alive 标签
<keep-alive>
组件的切换 路由 动态组件
</keep-alive>
内部的组件就会被缓存
1、有2个生命周期钩子函数
actived 激活触发
deactived 失活触发
2、语法
include=‘a,b‘ 名字叫a,b 的组件会被缓存
exclude=‘a,b‘ 除了a和b其他的组件缓存
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
注意:需要在组件创建的时候通过name:‘a‘,属性指定
### 动态路由 动态导航
{
path:‘/singer/:id‘
componet:Singer
}
直接修改动态导航时不会已引起组件的重新创建 组件是复用的
组件内的守卫
beforeRouterEnter 进入组件之前
beforeRouterUpdate
当前组件路由发生修改
动态导航修改组件复用不会重新创建销毁
监听路由发生改变
beforeRouterLeave 组件离开的时候触发
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
spa 首屏加载白屏问题
spa 会将所有的组件一次打包加载 加载过程中页面白屏
npm run build 编译打包
路由懒加载 异步引入组件 将组件实现按需引入
// import Recommend from ‘../components/Recommend‘
// import Singer from ‘../components/Singer/index.vue‘
// import Rank from ‘../components/Rank‘
// import My from ‘../components/My‘
// import Detail from ‘components/Detail‘
// 路由懒加载
const Recommend = ()=>import(‘../components/Recommend‘)
const Singer =()=>import(‘../components/Singer/index.vue‘)
const Rank =()=>import(‘../components/Rank‘)
const My =()=>import(‘../components/My‘)
const Detail =()=>import(‘components/Detail‘)
原文:https://www.cnblogs.com/imbacool/p/12458804.html