JavaScript
框架MVVM
模式angular
的模板
和数据绑定
技术react
的组件化
和虚拟 DOM
技术<template>
<div id="app">
<Main/>
</div>
</template>
<script>
import Header from '@/components/Layout/Header/Header';
import Main from '@/components/Layout/Main/Main';
import Navbar from '@/components/NavBar/NavBar';
import { mapState, mapActions } from 'vuex';
export default {
name: 'App',
components: {
Main
},
data() {
return {
route: this.$route
};
},
computed: {
...mapState({
isH5Page: state => state.setting.isH5Page,
activeNameText: state => state.setting.activeNameText
})
},
created() {
},
mounted() {
const screenWidth = document.body.clientWidth;
screenWidth >= 800 ? this.setPageAction(false) : this.setPageAction(true);
},
methods: {
...mapActions(['setPageAction', 'setActiveNameText'])
}
};
</script>
<style lang="scss">
#app {
height: auto;
min-width: 300px;
background-color: #fff;
}
</style>
html
页面JS
语法代码语法: {{exp}}
功能: 向页面输出数据
可以调用对象的方法
<span>{{ lang.mustChangePwd }}span>
<el-tag
v-for="(item, i) in data1" v-if="show > i"
:class="{wrap:wrap}" :key="item"
:style="{'font-size':fontSize || '13px'}"
>
{{getLabel(item)}}
</el-tag>
v-on:keyup='xxx'
v-on:keyup='xxx(参数)'
v-on:keyup.enter='xxx'
@keyup='xxx'
@keyup.enter='xxx'
<div @click="toLogin">
<i class="iconfont iconcuowu"></i>
</div>
在 computed
属性对象中定义计算属性的方法
在页面中使用{{方法名}}
来显示计算的结果
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
可以用来获取vuex
里的状态
computed: {
...mapState({
userInfo: state => state.user.userInfo,
isH5Page: state => state.setting.isH5Page
}),
...mapGetters(["language"])
},
计算属性高级
vm
对象的$watch()
或 watch
配置来监视指定的属性watch
只在被监听的属性值发生变化时执行.1.使用immediate: true
选项, 这样它就会在组件创建时立即执行.
watch: {
dog: {
handler(newVal, oldVal) {
console.log(`Dog changed: ${newVal}`);
},
immediate: true
}
}
2.使用deep: true
选项, 开启深度监听
watch: {
obj: {
handler(newVal, oldVal) {
console.log(`obj changed: ${newVal}`);
},
immediate: true,
deep: true
}
}
3.可只监听对象中的某一个key的变化
watch: {
'obj.hello': {
handler(newVal, oldVal) {
console.log(`obj changed: ${newVal}`);
},
immediate: true,
deep: false
}
}
4.computed
和 watch
的差异
computed
是计算一个新的属性,并将该属性挂载到 vm
(Vue 实例)上,而 watch
是监听已经存在且已挂载到 vm
上的数据,所以用 watch 同样可以监听 computed 计算属性的变化(其它还有 data、props)computed
本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed
属性,才会计算新的值,而 watch
则是当数据发生变化便会调用执行函数computed
适用一个数据被多个数据影响,而 watch
适用一个数据影响多个数据;class/style
绑定就是专门用来实现动态样式效果的技术:class='xxx'
'classA'
{classA:isA, classB: isB}
['classA', 'classB']
:style="{ color: activeColor, fontSize: fontSize + 'px' }"
activeColor/fontSize
是 data
属性v-if
与 v-else
v-show
v-show
较好v-if
的所有子节点不会解析(项目中使用)v-for / index
v-for / key
<template v-for="(val,index) in data">
<div :key="index" class="in-form" v-if="!val.hasOwnProperty('isShow') || val.isShow"></div>
</template>
v-on:xxx="fun"
@xxx="fun"
@xxx="fun(参数)"
event
$event
.prevent
: 阻止事件的默认行为 event.preventDefault().stop
: 停止事件冒泡 event.stopPropagation().keycode
: 操作的是某个 keycode 值的键.keyName
: 操作的某个按键名的键(少部分)beforeCreate()
created()
beforeMount()
mounted()
this.xxx = value
beforeUpdate()
updated()
vm.$destory()
beforeDestory()
destoryed()
created()/mounted()
: 发送 ajax
请求, 启动定时器等异步任务beforeDestory()
: 做收尾工作, 如: 清除定时器trasition
或 animation
xxx-enter-active
: 指定显示的 transitionxxx-leave-active
: 指定隐藏的 transitionxxx-enter/xxx-leave-to
: 指定隐藏时的样式
transition
opacity/其它
Vue.filter(filterName, function(value[,arg1,arg2,...]){
// 进行一定的数据处理
return newValue })
<div>{{myData | filterName}}</div>
<div>{{myData | filterName(arg)}}</div>
v:text
: 更新元素的 textContentv-htm
l : 更新元素的 innerHTMLv-if
: 如果为 true, 当前标签才会输出到页面v-else
: 如果为 false, 当前标签才会输出到页面v-show
: 通过控制 display 样式来控制显示/隐藏v-for
: 遍历数组/对象v-on
: 绑定事件监听, 一般简写为@v-bind
: 强制绑定解析表达式, 可以省略 v-bindv-model
: 双向数据绑定ref
: 指定唯一标识, vue 对象通过$refs 属性访问这个元素对象v-cloak
: 防止闪现, 与 css 配合: [v-cloak] { display: none }Vue.directive('my-directive', function(el, binding){
el.innerHTML = binding.value.toupperCase()
})
directives : {
'my-directive' : {
bind (el, binding) {
el.innerHTML = binding.value.toupperCase()
}
}
}
v-my-directive='xxx'
vue-cli
是 vue 官方提供的脚手架工具npm install -g
vue-cli vue init webpack vue_demo
cd vue_demo
npm install
npm run dev
访问: http://localhost:8080/
npm run build
npm install -g serve
serve dist
访问: http://localhost:5000
修改配置: webpack.prod.conf.js
output: { publicPath: '/xxx/' //打包文件夹的名称 }
重新打包:
npm run build
修改 dist 文件夹为项目名称: xxx
将 xxx 拷贝到运行的 tomcat 的 webapps 目录下
访问: http://localhost:8080/xxx
'rules': { 'no-new': 1 }
/* eslint-disable no-new */
new Vue({ el: 'body', components: { App } })
<template> 页面模板 </template>
<script>
export default {
data() {return {}},
methods: {},
computed: {},
components: {}
}
</script>
<style>样式定义 </style>
引入组件
映射成标签
使用组件标签
<template>
<HelloWorld></HelloWorld>
<hello-world></hello-world>
</template>
<script>
import HelloWorld from './components/HelloWorld'
export default {
components: {
HelloWorld
}
}
</script>
1.组件间通信基本原则
2.vue 组件间通信方式
props
2) $emit
3) 消息订阅与发布(如: pubsub
库) 4) slot
5) vuex
(后面单独讲)1.使用组件标签时
<my-component name='tom' :age='3' :set-name='setName'></my-component>
2.定义 MyComponent 时
在组件内声明所有的 props
方式一: 只指定名称
props: ['name', 'age', 'setName']
方式二: 指定名称和类型
props: {
name: String,
age: Number,
setNmae: Function
}
方式三: 指定名称/类型/必要性/默认值
props: {
name: {type: String, required: true, default:xxx},
}
注意:
1.绑定事件监听
// 方式一: 通过 v-on 绑定
@delete_todo="deleteTodo"
// 方式二: 通过$on()
this.$refs.xxx.$on('delete_todo', function (todo) {
this.deleteTodo(todo)
})
2.触发事件
// 触发事件(只能在父组件中接收)
this.$emit(eventName, data)
注意:
此方式只用于子组件向父组件发送消息(数据)
问题: 隔代组件或兄弟组件间通信此种方式不合适
此方式可实现任意关系组件间通信
(数据)
1.订阅消息
PubSub.subscribe('msg', function(msg, data){})
2.发布消息
PubSub.publish('msg', data)
3. 事件的 2 个重要操作(总结)
绑定事件监听 (订阅消息)
目标: 标签元素
事件名(类型): click/focus
回调函数: function(event){}
触发事件 (发布消息)
DOM 事件: 用户在浏览器上对应的界面上做对应的操作
自定义: 编码手动触发
此方式用于父组件向子组件传递标签数据
1. 子组件: Child.vue
<template>
<div>
<slot name="xxx">不确定的标签结构 1</slot>
<div>组件确定的标签结构</div>
<slot name="yyy">不确定的标签结构 2</slot>
</div>
</template>
2. 父组件: Parent.vue
<child>
<div slot="xxx">xxx 对应的标签结构</div>
<div slot="yyy">yyyy 对应的标签结构</div>
</child>
vue 插件, 非官方库, vue1.x 使用广泛
通用的 ajax 请求库, 官方推荐, vue2.x 使用广泛
https://github.com/pagekit/vue-resource/blob/develop/docs/http.md
npm install vue-resource --save
// 引入模块
import VueResource from 'vue-resource'
// 使用插件
Vue.use(VueResource)
// 通过 vue/组件对象发送 ajax 请求 this.$http.get('/someUrl').then((response) => {
// success callback
console.log(response.data) //返回结果数据
}, (response) => {
// error callback
console.log(response.statusText) //错误信息
})
https://github.com/pagekit/vue-resource/blob/develop/docs/http.md
npm install axios --save
// 引入模块
import axios from 'axios'
// 发送 ajax 请求
axios.get(url)
.then(response => {
console.log(response.data) // 得到返回结果数据
})
.catch(error => {
console.log(error.message)
})
npm install --save mint-ui
1. 下载
npm install --save-dev babel-plugin-component
2. 修改 babel 配置
"plugins": ["transform-runtime",["component", [
{
"libraryName": "mint-ui",
"style": true
}
]]]
main.js
import {Button} from 'mint-ui'
Vue.component(Button.name, Button)
App.vue
<template>
<mt-button @click="handleClick" type="primary" style="width: 100%">Test</mt-button>
</template>
<script>
import {Toast} from 'mint-ui'
export default {
methods: {
handleClick () {
Toast('点击了测试');
}
}
}
</script>
VueRouter(): 用于创建路由器的构建函数
new VueRouter({ // 多个配置项 })
路由配置
routes: [
{ // 一般路由
path: '/about',
component: About
},
{ // 自动跳转路由
path: '/',
redirect: '/about'
}
]
注册路由器
import router from './router'
new Vue({ router })
使用路由组件标签
1. <router-link>: 用来生成路由链接
<router-link to="/xxx">Go to XXX</router-link>
2. <router-view>: 用来显示当前路由组件界面
<router-view></router-view>
Home.vue
About.vue
<div>
<!--路由链接-->
<router-link to="/about">About</router-link>
<router-link to="/home">Home</router-link>
<!--用于渲染当前路由组件-->
<router-view></router-view>
</div>
export default new VueRouter({
routes: [
{
path: '/',
redirect: '/about'
},
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
}
]
})
import Vue from 'vue'
import router from './router'
// 创建 vue 配置路由器
new Vue({
el: '#app',
router,
render: h => h(app)
})
linkActiveClass: ‘active’, // 指定选中的路由链接的 class
News.vue
Message.vue
path: '/home',
component: home,
children: [
{
path: 'news',
component: News
},
{
path: 'message',
component: Message
}
]
<router-link to="/home/news">News</router-link>
<router-link to="/home/message">Message</router-link>
<router-view></route-view>
配置路由
children: [
{
path: 'mdetail/:id',
component: MessageDetail
}
]
路由路径
<router-link :to="'/home/message/mdetail/'+m.id">{{m.title}}</router-link>
路由组件中读取请求参数
this.$route.params.id
<router-view :msg="msg"></router-view>
<keep-alive>
<router-view></router-view>
</keep-alive>
vuex 管理的状态对象
它应该是唯一的
const state = { xxx: initValue }
const mutations = {
yyy (state, {data1}) {
// 更新 state 的某个属性
}
}
commit()
来触发 mutation
的调用, 间接更新state
$store.dispatch('action 名称', data1) // 'zzz'
const actions = {
zzz ({commit, state}, data1) {
commit('yyy', {data1})
}
}
$store.getters.xxx
const getters = {
mmm (state) {
return ...
}
}
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
import {mapState, mapGetters, mapActions} from 'vuex'
export default {
computed: {
...mapState(['xxx']),
...mapGetters(['mmm']), }
methods: mapActions(['zzz']) }
{{xxx}} {{mmm}} @click="zzz(data)"
import store from './store'
new Vue({ store })
一旦更新了 data 中的某个属性数据, 所有界面上直接使用或间接使用了此属性的节点都会 更新
a. 用来对 data 所有属性数据进行劫持的构造函数
b. 给 data 中所有属性重新定义属性描述(get/set)
c. 为 data 中的每个属性创建对应的 dep 对象
a. data 中的每个属性(所有层次)都对应一个 dep 对象
b. 创建的时机:
c. 对象的结构
{
id, // 每个 dep 都有一个唯一的 id
subs //包含 n 个对应 watcher 的数组(subscribes 的简写)
}
d. subs 属性说明
a. 用来解析模板页面的对象的构造函数(一个实例)
b. 利用 compile 对象解析模板页面
c. 每解析一个表达式(非事件指令)都会创建一个对应的 watcher 对象, 并建立 watcher 与 dep 的关系
d. complie 与 watcher 关系: 一对多的关系
a. 模板中每个非事件指令或表达式都对应一个 watcher 对象
b. 监视当前表达式数据的变化
c. 创建的时机: 在初始化编译模板时
d. 对象的组成
{
vm, //vm 对象
exp, //对应指令的表达式
cb, //当表达式所对应的数据发生改变的回调函数
value, //表达式当前的值
depIds //表达式中各级属性所对应的 dep 对象的集合对象 //属性名为 dep 的 id, 属性值为 dep
}
a. data 中的一个属性对应一个 dep, 一个 dep 中可能包含多个 watcher(模板中有几个 表达式使用到了同一个属性)
b. 模板中一个非事件表达式对应一个 watcher, 一个 watcher 中可能包含多个 dep(表 达式是多层: a.b)
c. 数据绑定使用到 2 个核心技术