vue是根据数据来构建用户界面的一套框架
<div id="app">
{{ msg }}
div>
<script src='vue.js'>script>
<script>
const app = new Vue({
el:"#app",
data:{
msg: 'hello vue'
}
})
script>
利用表达式进行插值,渲染到页面。所谓表达式就是有结果的一段代码。
语法:{{ 表达式 }}
注意:
1.使用的数据必须存在(data)
2.标签属性中不能使用
指令:带有v-前缀的特殊标签属性
作用:控制元素的显示和隐藏
v-show=“true/false”,使用display:none实现的,频繁切换显示隐藏的场景
v-if=“true/false”,通过判断条件来创建或移除元素节点,要么显示要么隐藏不频繁切换的场景
作用:辅助v-if进行判断渲染
作用:注册事件 = 添加监听 + 提供处理逻辑
语法:
v-on:事件名=“内联语句”
v-on:事件名=“methods中的函数名”
@事件名= “ ”
注意:methods里的函数的this指向创建的实例,如果要传参数这样写:@click=“fn(参数1,参数2)”
作用:动态的设置html的标签属性 -> src url title…
语法:v-bind:属性名=“表达式”,有省略的写法 :属性名=“表达式”
作用:基于数据循环,多次渲染整个元素 - > 数组、对象、数字…
语法:v-for=“(item每一项,index下标) in 数组”
v-for里面的key,给列表项添加的唯一标识符,便于vue进行列表项的正确排序复用
:key=“唯一标识符”
作用:给表单元素使用,双向数据绑定 -> 可以快速获取或者设置表单元素内容
v-model = '变量‘
通过 “.” 指明一些指令后缀,不同后缀封装了不同的处理操作 -> 简化代码
eg:
@keyup.enter 键盘回车监听
v-model.trim 去除首位空格
v-model.number 转数字
@事件名.stop 阻止冒泡
@事件名.prevent 阻止默认行为
v-bind对于样式控制的增强 - 操作class
:class=“对象/数组”
对象:键是类名,值为true有这个类,否则没有这个类
<div class="box" :class="{类名1: 布尔值,类名2: 布尔值}">div>
数组:数组中所有的类,都会添加到盒子上,本质上就是一个class列表
<div class="box" :class="[类名1,类名2]">div>
基于现有的数据,计算出来的新属性。依赖的数据发生变化,自动重新计算。
computed: {
计算属性名 () {
//基于现有的数据,编写求值逻辑
return 结果
}
}
computed 计算属性:封装了一段对数据的处理,求得一个结果
methods 方法:给实例提供一个方法,调用以处理业务逻辑
计算属性默认简写,只能读取访问,不能修改,要修改需要写计算属性的完整写法
computed: {
计算属性名: {
get() {
一段代码逻辑(计算逻辑)
return 结果
},
set(修改的值) {
//当计算属性的值被修改时,实行set
一段代码逻辑(修改逻辑)
}
}
}
作用:监视数据变化,执行一些业务逻辑或者异步操作
简单写法-简单类型数据,直接监视
data: {
words: '苹果',
obj: {
words: '苹果'
}
},
watch: {
//该方法会在数据变化时,触发执行oldValue一般不用,只有一个newValue
数据属性名 (newValue,oldValue) {
一些业务逻辑 或 异步操作
},
'对象.属性名'(newValue,oldValue) {
一些业务逻辑 或 异步操作
}
}
完整写法 -> 添加额外配置项
(1)deep: true 对复杂类型深度监视
(2)immediate:true 初始化立刻执行一次handler方法
data: {
obj: {
words: '苹果'
lang: 'italy'
},
},
watch: {
对象名: {
deep: true,
immediate: true, //初始化就立即执行,不必等到数据变化
handler (newValue) {
console.log(newValue)
}
}
}
vue生命周期:一个vue实例从创建到销毁的整个过程
阶段:
概念:vue生命周期过程中,会自动运行一些函数 -> 让开发者可以在特定阶段运行自己的代码
传统核心包开发模式:基于html、css、js文件,开发vue
工程化开发模式:基于构建工具(如webpack)的环境中开发vue
vue CLI是vue官方的一个全局命令工具,可以帮我们快速创建一个开发vue项目的标准化基础架子(webpack配置 )
使用步骤:
目录文件的截图
项目运行流程:npm run开始启动项目,之后加载 main.js,该js文件将app.vue(这个就是一开始学习写在标签里的模板)根组件渲染到 index.html 容器中展示页面。
//文件核心作用:导入App.vue,基于App.vue创建结构渲染index.html
//1、导入 Vue 核心包
import Vue from 'vue'
//2、导入 App.vue 根组件
import App from './App.vue'
//提示:当前处于什么状态(生产环境/开发环境)
Vue.config.productionTip = false
//1、Vue实例化。提供render方法 基于App.vue创建结构渲染index.html
new Vue({
render: h => h(App),
}).$mount('#app')//这一行的效果相当于 el: '#app'
组件化:一个页面可以划分成一个个组件,每个组件有着自己独立的结构、样式、行为。好处:便于维护,利于复用,提升开发效率。
组件注册的两种方式:
//比如在app.vue
//导入需要注册的组件
import 组件对象 from '.vue文件路径'
import HmHeaderr from './components/HHmHeader'
export default {
//局部注册
components: {
'组件名': 组件对象,
HmHeader: HmHeader
}
}
import HmButton from './components/HmButton'
// 调用Vue.component 进行全局注册
// vue.component('组件名',组件对象)
Vue.component('HmButton',HmButton)
结构template:只有一个根元素
样式style:全局样式(默认):影响所有组件;局部样式:scoped下样式,只作用于当前组件
逻辑scrript:el跟实例独有,组件中的data是一个函数,其他配置项一致
export default {
data () {
return {
count: 999
}
}
}
1.父子关系
props 和 $emit
父组件通过props将数据传递给子组件,子组件利用 $emit通知父组件修改更新
父组件先动态绑定属性值,然后子组件通过prpos:{‘属性名’}来接受父组件的值
vuex
2.非父子关系
provide & inject
eventbus
vuex
定义:组件上注册的一些自定义属性
作用:向组件传递数据
特点:任意数量,任何类型
props: {
校验的属性名: 类型
}
props: {
校验的属性名: {
type: 类型,
required: true,//是否必填
default: 默认值,//默认值
validator (value){
//自定义校验逻辑
return 是否通过校验
}
}
}
单向数据流:子组件要修改父组件传来的值,只能告诉父组件让父组件改
prop:外面传进来的值,不能随便改
data:自己的值,随便改
<div id = "app">
<input v-model="msg" type="text">
<input :value="msg" @input="msg = $event.target.value" type="text">
div>
步骤:
//子组件Sun
<select :value="CityId" @change="handleChange">
<option value="102"></option>
</select>
props: {
cityId: String
},
methods: {
handleChange(e){
this.$emit('事件名',e.target.value)
}
}
//父组件
<faSelect :cityId="selected" @事件名="selected = $event"></faSelect>
以上代码的简化:
//子组件
<select :value="value" @change=“handle”>
<option value="102"><.option>
</select>
props: {
value: Number
},
methods: {
handle(e){
this.$emit('input',e.target.value)
}
}
//父组件
<select v-model="selectId "/>
作用:可以实现子组件与父组件数据的双向绑定
特点:prop属性名,可以自定义,非固定为value
场景:封装弹框类的基础组件,visible属性true显示fale隐藏
// 父组件
<BaseDia :visible.sync="isShow"/>
---------------------------------上下一样
<BaseDia :visible="isShow" @update:visible="isShow = $event"/>
// 子组件
props: {
visible: Boolean
},
this.$emit('update:visable',false)
作用:利用ref和$refs可以用于获取dom元素,或者组件实例
特点:查找范围 当前组件内
第一步:找到目标标签,添加 ref 属性
<div ref="charRef">111div>
第二步:恰当时机,通过this.$refs.xxx获取目标元素
mounted () {
console.log(this.$refs.charRef)
}
第一步:找到目标组件添加 ref 属性
<BaseForm ref="baseForm">BaseForm>
第二步:恰当时机,通过 this.$refs.xx获取目标组件,就可以调用组件对象里面的方法
this.$refs.baseForm.组件方法()
//这段代码起不到作用,第一句异步更新,第二句会再第一句前面执行
handleEdit () {
//1.显示输入框
this.isShowEdit = true
//2.让输入框获取焦点
this.$refs,inp.focus()
}
// 修改代码
handleEdit () {
//1.显示输入框
this.isShowEdit = true
//2.让输入框获取焦点
this.$nextTick(()=>{
this.$refs,inp.focus()
})
}
Vue.directive('指令名'.{
//inserted 会在指令所在的元素插入到页面中的时候出发
inserted (el) {
//el 就是指令所绑定的元素
el.focus()
}
})
directives: {
"指令名": {
inserted () {
//可以对el标签,扩展额外功能
el.focus()
}
}
}
需求:实现一个color指令 - 传入不同的颜色,给标签设置文字颜色
<div v-color="color1">我是内容div>
data () {
return {
color1: red
}
},
directives: {
color: {
//提供的是元素被添加到页面中时的逻辑
inserted (el,binding) {
el.style.color = binding.value
},
//指令的值的修改的时候触发,提供值变化后,dom更新的逻辑
update (el,binding) {
el.style.color = binding.value
}
}
}
作用:让组件内部的一些结构支持自定义
用法:
第一步:将希望自定义组件的某部分使用 slot 占位
<template>
<div>111div>
<slot>slot>
<div>div>
template>
第二步:在使用组件的地方自由定制
<TodoList>
<span>我在这里自定义,将在slot部位显示span>
TodoList>
只需要在 slot 部位写入默认值就可以,当使用插槽的时候自定义的内容就会覆盖掉默认内容
作用:组件内有多处需要自定义
<div>
<slot name="head">slot>
div>
<div>
<slot name="content">slot>
div>
<div>
<slot name="footer">slot>
div>
<MyDialog>
<template v-slot:head>
自定义内容1
template>
<template v-slot:content>
自定义内容2
template>
<template #footer>
自定义内容3
template>
MyDialog>
npm
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter()
new Vue({
render: h => h(App),
router
}).$mount('#app')
两个核心的步骤
import Find from './views/Find.vue'
import My from './views/My.vue'
import Friend from './views/Friend.vue'
const router = new VueRouter({
routes: [
{path: '/find',component: Find},
{path: '/my',component: My},
{path: '/friend',component:Friend},
]
})
2.配置导航,配置路由出口(路径匹配的组件显示的位置)
<div class="footer_wrap">
<a href="#/find">发现音乐</a>
<a href="#/my">我的音乐</a>
<a href="#/friend">朋友</a>
</div>
<div class="top">
<router-view></router-view>
</div>
vue-router 提供了一个全局组件 router-link(取代a标签)
router-link-active 模糊匹配 to=“/my"可以匹配 /my /my/a /my/b …
router-link-exact-active 精确匹配 to=”/my" 只可以匹配 /my
如何自定义这两个类名
const router = new VueRoouter({
routes:[...],
linkActiveClass:'类名1',
linkExactiveClass:'类名2'
})
const router = new VueRouter({
routes: [
...,
{
path: '/search/:参数名',
component: Search
}
]
})
可选符 ?
如果按照第一步那样配置参数名的话在跳转链接的时候就必须有参数名,如后面增加可选符的话有没有参数就都可以 path: ‘/search/:参数名?’,
问题:网页打开后,url是默认路径 / ,未匹配到组件时会出现空白
重定向:匹配到某一路径的时候,强制跳转到某一路径
const router = new VueRouter({
routes: [
{path: '/',redirect: '/home'},
{path: '/home',component: Home},
]
})
作用:当路径找不到匹配时,给一个提示页面
位置:在路由地址配置项的最后
const router = new VueRouter({
routes: [
{path: '/',redirect: '/home'},
{path: '/home',component: Home},
{path: '*',component: NotFind} //当前面两个选项都匹配不到的时候就轮到这行了
]
})
const router = new VueRouter({
routes: [
{path: '/',redirect: '/home'},
{path: '/home',component: Home},
{path: '*',component: NotFind} //当前面两个选项都匹配不到的时候就轮到这行了
],
mode: "history"
})
methods: {
goSearch() {
//通过路径的方式跳转
// 1
this.$router.push('/search')
// 2
this.$router.push({
path: '/search'
})
}
}
//通过命名路由的方式跳转,适合名字长的
const router = new VueRouter({
routes: [
{path: '/',redirect: '/home'},
{name: 'search' path: '/home',component: Home},
{path: '*',component: NotFind} //当前面两个选项都匹配不到的时候就轮到这行了
],
mode: "history"
})
methods: {
goSearch() {
this.$router.push({
name: 'search'
})
}
}
// 通过路径参数传参
data () {
return {
inpvalue: ''
}
},
methods: {
goSearch() {
//通过路径的方式跳转
// 1
this.$router.push(`/search?key=${this.inpvlaue}`)
// 2
this.$router.push({
path: '/search',
query: {
key: this.inpValue
}
})
}
}
//接受key
{{this.$route.query.key}}
// 动态路由传参
methods: {
goSearch() {
//通过路径的方式跳转
// 1
this.$router.push(`/search/${this.inpValue}`)
// 2
this.$router.push({
path: `/search/${this.inpValue}`
})
}
}
//接受
$route.pramas.words
概念:是Vue的内置组件,当他包裹动态组件的时候,会缓存不活动的组件实例而不是销毁他,同时有了新的钩子函数,同时他是一个抽象组件,自身不会渲染DOM元素。
能解决的问题:在组件切换过程中可以避免组件的多次重复渲染,减少了加载时间,提高用户体验
三个属性:
新的两个生命周期钩子:
1.是什么?
vuex是一个vue的状态(数据)管理工具。vuex是一个插件,可以帮我们管理vue通用的数据(多组件共享的数据)
2.场景
某个状态在很多个组件来使用,多个组件共同维护一份数据
//创建数据
const store = new Vuex.Store({
state: {
count: 100
}
})
// 使用方法
// 模板中: {{$store.state.xxx}}
// 逻辑组件中:this.$store.state.xxx
// JS模块中:store.state.xxx
以上代码可以通过辅助函数 mapState() 帮助我们把store中的数据自动映射到组件的计算属性中
// 在需要的组件中先导入这个函数
import {mapState} from 'vuex'
// 计算属性中使用
computed: {
...mapState(['count'])
}
// 模板中使用: {{ count }}
vuex同样遵循单向数据流,组件中不能直接修改仓库里的数据(strict: ture可以开启严格模式)
mutations可以来修改state数据。(state数据的修改只能通过它)
const store = new Vuex.Store({
state: {
count: 100
},
mutations: {
add (state) {
state.count += 1
}
}
})
// 组件中调用mutations
this.$store.commit('add')
mutations的传参语法
mutations: {
add (state,n) {
state.count += n
}
}
// 组件提交中调用
this.$store.commit('add',10)
mapMutations把位于mutations中的方法提取出来,映射到组件methods中
mutations: {
add (state,n) {
state.count += n
}
}
// 组件中直接调用这个方法
import {mapMutations} from 'vuex'
methods: {
...mapMutations({'add'})//相当于组件中有了这个函数
}
相比于mutations同步处理数据,便于监测数据变化,记录调试,actions能处理异步操作
// 组件中调用actions中的方法
methods: {
change () {
this.$store.dispatch('方法名',载荷)
}
}
// 提供actions方法
actions: {
方法名 (context, 载荷) {
setTimeout(()=>{
context.commit('m中的方法',载荷)
})
}
}
// mutations 中接受 a'ctions
mutations: {
m中方法 (state,载荷){
state.count = 载荷
}
}
mapActions…也是映射到组件的methosd方法中
类似于之前的计算属性,有时候我们还需要从state中派生出一些状态,这些状态依赖state,此时会用到getters
getters: {
filterList (state) {
return state.list.filter(item => item > 5)
}
}
组件中访问getters的方法有两种:
底层:{{ $store.getters.filterList }}
通过辅助函数:在计算属性中注册,在模版中直接插入表达式
辅助函数小结:
state和getters都是在组件的计算属性中注册
mutations和actions是在组件的方法中注册
解决的问题:因项目太大而导致的state臃肿不以维护,从而将他拆解成多个模块。
// 创建小的模块 store/modules/user.js
const state = {
userInfo: {
name: ‘zjx’
age: 18
}
}
const mutations = {}
const actions = {}
const getters = {}
export default {
state,
mutations,
actions,
getters
}
// 将小的模块挂载到main.js中的store中
import user from ‘./modules/user’
const store = new Vuex.Store({
modules: {
user
}
})
默认模块(没有开启命名空间)mutation 和 actions会被挂载到全局,只有开启命名空间,才会挂载到子模块