vue
基本概念区分
- 单页面应用:在一个页面跳来跳去,不重新加载页面
- vue 特点:渐进式 框架 双向数据绑定
- 双向数据绑定:视图改变 数据自动更新;数据更新 视图自动改变
- 渐进式:vue vue-router路由 vuex axios
- 框架:自己写的代码被框架调用(库:自己调用库的代码)
- 声明式
安装vue
cmd命令
npm i vue
yarn add vue
vue核心实现方法
var obj={}
Object.defineProperty(obj,'name',{
value:'xhufeng',
configurable:true,//是否可删
writable:true,//是否可写
enumerable:true,//是否可枚举(循环)
set(val){
//只要外界给name赋值,就会触发该函数
//形参val就是外界赋予的值
},
get(){
return 123
}
})
复制代码
vue指令
指令都是行内属性
v-model
放在input、textarea、select>option上的,实现双向数据绑定v-text
展示对应的文本v-once
对应的标签只渲染一次v-show=布尔
是否能显示,true能显示,false不能显示(存在隐式转化)v-html
把值中的标签渲染出来
v-for
循环显示元素
可以循环数组、对象、数字、字符串
最好加:key='a+i'
v-for='item in ary'
v-bind
用于绑定行内属性 简写成
:
v-if
控制是否渲染该元素
值是true,则渲染该元素;false则不渲染
与v-else v-else-if
连着使用
可以使用template标签,就不会出现多余标签
<body>
<div id="app">
<h1>{{name}}</h1>
<button @click='flag=!flag'>按钮</button>
<h2 v-show='flag'>hello</h2>
<h2 v-show='!flag'>world</h2>
<button @click='n=1'>1</button>
<button @click='n=2'>2</button>
<button @click='n=3'>3</button>
<h3 v-if='n===1'>hello</h3>
<h3 v-else-if="n===2">hahaha</h3>
<h3 v-else>world</h3>
</div>
</body>
</html>
<script src="./node/node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
name: "珠峰",
flag:true,
n:1
},
methods: {
fn() {
}
}
})
</script>
复制代码
v-cloak
需要配合css使用:解决小胡子显示问题
v-pre
跳过有这个指令的标签及其子元素的编译,按照原生代码编译
vue对象
data中的属性最终都添加到了实例上 属性需要有get set,才能触发视图更新
let vm = new Vue({
el: '#app',
data: {
name: 'liu',
age:21,
q:'<h1>haha</h1>',
obj:{
a:123,//对于对象来说,新增一个属性不会触发视图更新,只有改变属性时才会触发视图更新
b:undefined,
}
}
}).$mount('#app')
//处理方式
//1.正常写全要用到的属性;先预留要用到的属性
//2.整个对象的重新赋值
//3.$set()方法
vm.$set(vm.obj,'c','456')
//4.增加一个无关变量t,每次修改完数据之后;重置t就可以了
复制代码
vue数组
let vm = new Vue({
el: '#app',
data: {
ary: [1, 2, 3, 4]
}
})
vm.ary.length--;
//能改变原有数组,但不能触发视图更新,只有数组原型上的变异方法可以触发更新
//数组变异方法:pop shift unshift push reverse splice sort
复制代码
vue 事件
<body>
<div id="app">
{{ary}}
<button @click='fn'>按钮1</button>
<button @click='fn(name,$event)'>按钮2</button>
<!-- $event是固定写法,代表传参事件对象 -->
</div>
</body>
</html>
<script src="./node/node_modules/vue/dist/vue.js"></script>
<script>
//事件绑定,用v-on:事件类型=‘函数’ 或者 @事件类型=‘函数’
//函数一般是在methods中定义的
//对应的函数一般不带小括号,默认传参事件对象e
//当我们需要传参时,需要加小括号,小括号里写需要传的参数;当只有小括号没有传参时,为undefined
//el data methods 都是VUE规定死的属性名
let vm = new Vue({
el: '#app',
data: {
ary: [1, 2, 3, 4],
name:'liu'
},
methods: {
fn: function (val,e) {
console.log(val,e,this)
}
}
})
//@kryup.13='fn'在按下回车的时候才会触发该函数
</script>
复制代码
vue过滤器
全局用filter,实例局部使用filters 全局过滤器要放在需要使用的实例的前面
vue计算属性computed
- 于data同级别
- 语法同methods一样
- 计算属性的名字 不能跟 data 或 methods 中的名字重复
- 完全依赖于函数体中出现的属性名,只在最初加载时和其中属性名改变时运行,并不是像methods中的函数只要页面更新就运行一次
- 不能传参
- 异步的无法处理
- 为了提高性能而存在
vue监听属性
- 当且仅当监听的属性(例如:name)发生变化时会执行函数
- 可以处理异步
- 下面这种写法不能监听引用数据类型的内部变化
watch:{
name(newV,oldV){
clearTimeout(this.timer)
this.timer=setTimeout(() => {
if (newV.length > 5) {
this.msg2 = '名字太长'
}else{
this.msg2 = ''
}
}, 500)
}
}
复制代码
- 深度监听需要用下面这种语法
- 这种深度监听在有get和set属性时才会触发监听
watch:{
obj:{
handler(){
console.log(1111)
},
deep:true
}
}
复制代码
directives自定义指令
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
vue动画
transition
- 把需要实现动画的标签用transition标签包起来
- 只能对根元素有动效
transition-group
- tag指定外层包裹元素的tag类型;不写,默认span
- duration控制vue设置的类名存在的时间
事件修饰符
.self
只点元素本身时才触发事件.stop
阻止冒泡事件.prevent
阻止默认事件.once
对应函数只触发一次.capture
在捕获阶段触发二级绑定事件.passive
优先执行默认事件(滚动行为)
表单修饰符
.number
转化为数字,类似parse转化.trim
去字符串前后空格
生命周期
let vm = new Vue({
el:'#app',
// template:'<h1>哈哈哈</h1>',
data:{
name:"liu"
},
// 生命周期钩子函数 就是VUE规定的一些在固定阶段执行的函数
// 语法上 跟 data和el、methods等 同级
beforeCreate(){
// 创造之前
// 不能获取data和methods里的数据
console.log('beforeCreate');
debugger;
},
created(){
// 能获取data和methods里的数据
// 一般把ajax请求的发送写到这里
},
beforeMount() {},
mounted(){
// 在此时DOM已经渲染完成
},
beforeUpdate(){
// 在视图更新时会触发其中函数
// 函数在视图更新前执行
},
updated(){
// 在视图更新时会触发其中函数
// 函数在视图更新后执行
// 不要写会触发视图更新的代码
},
beforeDestroy(){},
destroyed(){}
})
vm.$destory();//手动销毁该实例,双向数据绑定没了
复制代码
组件
- 划分比较明细,复用率比较高
- 功能性组件 页面级组件
- 全局组件 局部组件
- template模板中只能有一个根元素
全局组件的注册
- 必须写到根组件(根实例)的前面
//全局组件的定义
Vue.component('qqq',{
template:'<i>hello 小聪子</i>'
})
复制代码
<body>
<div id="app">
<h1>{{name}}</h1>
<aaa></aaa>
<aaa></aaa>
<my-name></my-name>
<!-- 不支持驼峰式命名 -->
</div>
</body>
<template id='qqq'>
<div>
<input type="text" v-model='name'>
<h1><i>{{name}}</i></h1>
</div>
</template>
<script>
//全局组件的定义
//使用时只要把组件名当作标签使用即可
Vue.component('aaa', {
//没有el属性,有template属性,data是个函数,并且返回一个对象
//template就是qqq标签要去展示的内容
//template有且只能有一个根元素
template: '#qqq',
data() {
return {
name: 'liu'
}
},
created() {
console.log(this.name)
}
})
Vue.component('myName', {
template: `<h2>My name is </h2>`,
data() {
return {
}
},
})
let vm = new Vue({
el: '#app',
data: {
name: "liu"
}
})
</script>
复制代码
局部组件的注册
- 局部组件只能使用在此之前声明的局部组件作为子组件
<body>
<div id="app">
<h1>{{name}}</h1>
<son></son>
<parent></parent>
</div>
</body>
<template id="opp">
<h2>ninininini</h2>
</template>
<template id="o">
<h2>小聪子<son></son></h2>
</template>
<script>
let son = {
template: '#opp',
data() {
return {
}
}
}
let parent = {
template: '#o',
data() {
return {
}
},
components: {
son
}
}
let vm = new Vue({
el: '#app',
data: {
name: "liu"
},
components: {
son,
parent: parent
}
})
</script>
复制代码
组件的数据传输
父传子
过程
- 1.通过v-bind绑定属性,把相应的数据传递给子组件
- 2.子组件通过props接收传进来的数据
注意事项
- 父传子是单向数据流,不能从子组件修改父组件的数据
- 但如果是引用数据类型,不修改地址,只改变内容,可以改变
- props可以是数组,也可以对象
- props中自定义属性的参数
-
- 1.default:默认值 复制代码
-
- 2.type:规定此属性的数据类型 复制代码
- 可以通过实例
this.$parent
调用父组件的数据和方法(不推荐)
<body>
<div id="app">
<h1>{{name}}</h1>
<input type="text" v-model='name'>
<son :name='name'></son>
</div>
</body>
<template id="o">
<div>
<h3>{{name}}</h3>
<button @click='fn'> 这个按钮点击了{{n}}次</button>
</div>
</template>
<script>
let son = {
template: '#o',
data() {
return {
n: 0
}
},
methods: {
fn() {
this.n++
}
},
props:['name']
}
let vm = new Vue({
el: '#app',
data: {
name: "liu"
},
components: {
son,
}
})
</script>
复制代码
子传父
本质上是父组件使用子组件的数据
官方过程
- 通过自定义事件触发父组件中的方法
- 再由子组件方法的执行通过
this.$emit('自定义事件名',this.qqq)
传递子组件的数据也可以在父组件中通过
this.$children[i]
调用子组件的数据及方法 也可以在父组件中通过this.$refs.son
调用子组件的方法
插槽
在template模板中写入
<slot></slot>
,可显示在使用组件时组件名标签内部内容
具名插槽
在slot标签中的name属性是控制要去显示哪一部分的一个功能 不写时,默认default,全部显示 name对应的的是
slot='qqq'
的部分
模板中若有与name值对应的元素,则slot标签包含的内容不会显示出来;反之,可以显示
子父组件的mounted
执行顺序
动态组件component
keep-alive
-在没有keep-alive时,component组件是销毁旧的,重新渲染新的 -加上keep-alive后,动态组件有缓存机制,不会销毁旧的
<keep-alive>
<component :is='son'></component>
</keep-alive>
复制代码
vue-router
vue-router是vue的路由插件
基本用法
- 步骤
- 1、声明组件
- 2、编写路由映射表
- 3、把编辑好的映射表注入到router实例中
- 4、把router实例注入到根实例中
- router-link 控制跳转的链接和显示的文字
- router-view 控制显示的组件内容
- active-class 控制选中对应路径的类名
- tag 控制渲染成什么标签
<body>
<div id="app">
<router-link to='/home' active-class='current'>首页</router-link>
<router-link to='/list' tag='div'>列表</router-link>
<router-view></router-view>
</div>
</body>
</html>
<template id="home">
<div>home</div>
</template>
<template id="list">
<div>list</div>
</template>
<script src="../node/node_modules/vue/dist/vue.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
<script>
let home = {
template: '#home',
}
let list = {
template: '#list',
}
//路由映射表
let routes = [{
path: '/home',
component: home
},
{
path: '/list',
component: list
}
]
let router=new VueRouter({
routes:routes,
})
let vm = new Vue({
el: '#app',
data: {
name: "liu"
},
router,
})
</script>
复制代码
传参
- 提供了两种传参方式
- 1、query传参(问号传参)
- 路由映射表不用改动
:to={path:'',query:{}}
或者:to={name:'',query:{}}
- 2、params传参(路径传参)
- 在映射表中添加
/:变量
的形式;:to={name:'',params:{变量:''}}}
<router-link :to='{path:"/list",query:{id:123,e:name}}' tag='div'>列表</router-link>
重定向redirect
let routes = [
{
path:'/',
redirect:'/son2/222'
},
{
path:'/son1',
// redirect:'/son2/5555',
name:'son1',
component:son1,
redirect:'/son1/sz',
children:[
{
path:'/son1/sz',
component:sz
}
]
},
{
path:'/son2/:bl1234',
name:'son2',
component:son2
},
{
path:'/*',
redirect:'/son1'
}
]
复制代码
vuex
是一个能方便vue实例及其组件传输数据的插件 方便传输数据,作为公共存储数据的一个库
基本用法
- 步骤
- 1、创建一个vuex实例
- 2、在根组件中注册一下
- 3、注册后,根组件及其一下的局部或全局组件可使用vuex实例中的数据方法,多个组件使用同一套规则时,我们可以把这套规则单独拎出来写在vuex实例中通用
方法汇总
state
类似vue实例中的data,存储数据 在vue实例中用
this.$store.state
调用state里的数据 使用...Vuex.mapStore(['count'])
将其数据放入computed中
mutations
官方提供的唯一改数据的方法 其中必须是同步函数 通过
commit
来调用mutations中的函数 其中函数最少有一个参数state
,最多两个参数另加val
(调用时的传参) 使用...Vuex.mapMutations(['mu_add'])
将其函数放入methods中
actions
可以写异步函数,一般多用于触发ajax请求 不能直接用于修改state中的数据,需要通过其中函数默认的第一个实参obj,用
obj.commit('mu_')
来调用mutations中的函数来修改数据 使用...Vuex.mapActions(['ac_add'])
将其函数放入methods中
getters
类似vue实例中的计算属性,存储数据 使用
...Vuex.mapGetters(['remove'])
将其函数放入computed中
//1、创造一个vuex实例
//2、把创造的实例放到根实例中
//使用this.$store.state
let son1 = {
template: `<div>
<button @click='add'>增加</button>
<button @click='mu_add(100)'>增加</button>
<button @click='add2(100)'>2增加</button>
<h2>{{count}}</h2>
<h2>{{qqq}}</h2>
</div>`,
data() {
return {
}
},
computed: {
//两种监听vuex数据的写法
// myCount(){
// return this.$store.state.count
// }
...Vuex.mapState(['count', 'qqq'])
},
methods: {
add() {
// this.$store.state.count++
// this.$store.commit('mu_add', 1)
this.mu_add(10)
},
...Vuex.mapMutations(['mu_add']),
add2() {
this.$store.dispatch('ac_add', 22)
//dispatch 触发的是actions里的函数
//commit 触发的是mutations里的函数
}
}
}
let son2 = {
template: `<div>
<button @click='remove'>减少</button>
<h2>{{$store.state.count}}</h2>
</div>`,
methods: {
remove() {
this.$store.commit('mu_remove', 1)
}
},
}
let store = new Vuex.Store({
state: {
count: 0,
qqq: 12
},
mutations: {
mu_add(state, val = 1) {
console.log(arguments)
//第一个实参是默认传的state
//第二个实参是自己传的参数
//一共只有一个或两个实参
state.count += val
},
mu_remove(state, val = 1) {
console.log(arguments)
//第一个实参是默认传的state
//第二个实参是自己传的参数
//一共只有一个或两个实参
state.count -= val
}
},
actions: {
ac_add(obj,n) {
//obj是vuex封装好的一个对象,里边提供了commit方法
obj.commit('mu_add',n)
console.log(arguments)
}
}
//mutations中必须是同步函数,actions同步异步都行
//想要修改state里的数据只能用commit来调用mutations里的函数
})
let vm = new Vue({
el: '#app',
store,
data: {
name: "liu"
},
components: {
son1,
son2
},
created() {
console.log(this)
},
})
复制代码
==========================================================
前端小白,第一次发文,欢迎评论指正!