有关vue双向数据绑定实现原理请移步juejin.cn/post/696760…
1. vue 基础部分
- 1.1 组件模版
<template>
<div class="Name">
<div ref="msgDiv">这是一个组件模版</div>
<ChildCompnent v-if="ifRenderChildCompnent" ref="childCompnent" :visible.sync="childCompnentVisible" @hook:mounted="onChildCompnentMounted" />
</div>
</template>
<script>
export default {
name: 'String',
components: {}, // {组件1,组件2},所导入组件名
props: {// 组件父组件传递值,推荐用对象形式
yearlimit: {
type: Array, // 注意若类型为Object||Array,default的值必须用工厂函数返回
default: function() {
return []
// [min,max]
}
}
},
data() {
return {
ifRenderChildCompnent: true,
childCompnentVisible: false, // 子组件 this.$emit('update:childCompnentVisible',value)
dataobj: { key: 'value' }
}
}, // 组件数据源
beforeCreate() {
// alert("创建vue实例前")
},
created() {
// alert("实例创建完成")
},
beforeMount() {
// alert("虚拟dom开始挂载到实际dom树中")
},
mounted() {
// alert("虚拟dom已经挂载到实际dom树中,页面加载完成")
// this.$refs.childCompnent 子组件实例化对象,注意观察这个示例里面的数据结构
// this.$refs.msgDiv dom节点,注意观察dom节点对象数据结构
// this.$parent 父亲组件实例化对象
},
beforeUpdate() {
// alert("更新前")
},
updated() {
// alert("更新完成")
},
beforeDestroy() {
// alert("销毁前")
},
destroyed() {
// alert("销毁完成")
},
// 以上8个为vue的一个生命周期
activated() {
// 在vue对象存活的情况下,进入当前存在activated()函数的页面时,一进入页面就触发;可用于初始化页面数据等,与keepAlive对应
},
beforeRouteEnter(to, from, next) {
// 进入路由前
console.log(this, 'beforeRouteUpdate') // undefined
next(vm => {
// 当钩子执行前,组件实例还没被创建
// vm 就是当前组件的实例相当于上面的 this,所以在 next 方法里你就可以把 vm 当 this 来用了。
console.log(vm) // 当前组件的实例
})
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 对于一个带有动态参数的路径 /good/:id,在 /good/1 和 /good/2 之间跳转的时候,
// 由于会渲染同样的good组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
console.log(this, 'beforeRouteUpdate') // 当前组件实例
next()
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
console.log(this, 'beforeRouteLeave') // 当前组件实例
next()
},
computed: { // 计算属性
key() { // 这里的key相当于date里面的数据源,不能在data里面重复定义
return 'a newValue by calculating and refining known properties in data'
// return a value(必须)
}
},
filters: { // 过滤器,对一些绑定值进行过滤筛选,比如只允许输入数字 v-model=”value| filterDigital”
filterName(value) {
return 'a newValue by filter the value'
}
},
methods: {
reRenderChildCompnent() { // 子组件 销毁重载
this.ifRenderChildCompnent =false
this.$nextTick(()=>{
this.ifRenderChildCompnent =true
})
},
methodName(arg) {
// 要执行的操作
},
onChildCompnentMounted() {
setTimeout(()=>{
console.log(this)
debugger
// 浏览器里再次console.log(this)
// 注意理解箭头函数里面的this指的是 运行环境上下文 的this
},10)
// 子组件mounted回调
}
},
watch: {
dataobj: {
handler() {
// 要执行的操作
},
deep: true, // 是否深度监听,意为对象dataobj内部任何属性发生变化则全局重新渲染
immediate: true // 代表在watch里声明了dataobj这个方法之后立即先去执行handler方法
}
}
}
</script>
<style lang="scss">
</style>
- 1.3 vue 指令
<template>
<div class="hello">
<!-- v-bind:attrname="attrnamevalue"-->
<!-- {{}} -->
<h1 class="h1class">
<span>
sass测试
</span>
</h1>
<div v-show="showtype">
<h1 :class="{ active: isActive, 'text-danger': hasError }" :attrname="attrnamevalue">{{ msg }}</h1>
<h1 v-bind="{attrname1:(attrnamevalue1=='attr1'?'0':'1')?'a':b,attrname2:attrnamevalue2}">多个属性绑定案例</h1>
<h1 :attrname="attrnamevalue">这是attrname</h1>
<h1>{{text}}</h1>
<h1 style="color: #ae00ff">{{computedh1value2hastag}}</h1>
<h1>{{h1value2hastag?'这是一个双大括号文本text1':'这是一个双大括号文本text2'}}</h1>
<h1>{{h1value2hastag?'<span>这是一个双大括号文本text</span>':'这是一个双大括号文本text'}}</h1>
<br>
<!-- v-text="text" -->
<div v-text="text"></div>
<br>
<!-- v-html="html" -->
<div style="color:#f00" v-html="text"></div>
<div style="color:#f00" v-html="h1value2hastag?'<span>这是一个绑定标签文本text</span>':'这是纯文本text'"></div>
<br>
<!-- v-model="value" -->
<Input v-model="value" readonly placeholder="Enter something..." style="width: 300px" />
<Input v-model="radominputvalue" placeholder="Enter something..." style="width: 300px" />
<br>
<br>
<input id="ceshiid" type="text" readonly value="绑定不同事件类型对象语法" v-on="{blur:inputblur,focus:inputfocus}" />
<input type="text" readonly value="绑定不同事件类型分开绑定" @blur="inputblur" @focus="inputfocus" />
<br>
<br>
<!-- v-on:click="buttonalert(123)"-->
<Button type="primary" v-on:click="buttonalert1(123)">getinputvalue</Button>
<Button type="primary" v-on:click="buttonalert1(123);buttonalert2(234)">绑定不同方法</Button>
<Button type="primary" v-on:click="buttonalert3(123);buttonalert3(234)">重复绑定某个方法</Button>
<br>
<!-- v-if="isshowdiv1" -->
<div class="div1" style="height:100px;background:#0f0" v-if="isshowdiv1"></div>
<!-- v-show="isshowdiv2" -->
<div class="div2" style="height:100px;background:#00f" v-show="isshowdiv2"></div>
<br>
<!-- v-for="(item,index) in acdatelist" :key="index" -->
<ul>
<li v-for="(item,index) in datelist" :key="index" :attr="index" :ref="'li'+index" class="fn-inline" @click="setlivalue(index)">
datelist{{index}}的值为{{item}}
</li>
</ul>
<Button type="info" v-on:click="getrefs">getrefs</Button>
<!-- 绑定Class -->
<h1 :class="isactive ? 'active fn-inline' : 'fn-inline'">以条件语法绑定一个属性值</h1>
<h1 :class="{class1:isaddclass1,class2:isaddclass2}">对象语法绑定一个属性的多个值</h1>
<br>
<!-- 深拷贝解决监听层级比较深的数据的改变前后值变化 -->
<ul>
<li
v-for="(item,index) in acdatelist"
:key="index"
:style="{
'--background': colorBgConfig[index].color + '15',
'--background-active': colorBgConfig[index].color,
'--background-hover': colorBgConfig[index].color,
}"
:class="activeLiIndex===index?'active':''"
class="list fn-inline"
@click="setlivalue(index)">
datelist{{index}}的值为{{item | valuetofixed(1) | unitvalue}}
</li>
</ul>
<!-- 计算属性 -->
<Input v-model="inputcountvalue1" placeholder="Enter something..." style="width: 300px" />
<span >*</span>
<Input v-model="inputcountvalue2" placeholder="Enter something..." style="width: 300px" />
<span >=</span>
<Input v-model="inputcountedvalue " placeholder="Enter something..." style="width: 300px" />
<br>
<br>
<br>
<!-- 路由 -->
<!-- <Button type="success" :click="gorouter('Component1')">gorouterComponent1</Button> -->
</div>
<br>
<br>
<Button type="success" @click="gorouter('Component2')">gorouterComponent2</Button>
<Button type="success" @click="gorouter('Component1')">gorouterComponent1</Button>
<Button type="success" @click="gorouter('Table')">gorouterTable</Button>
<br>
<br>
</div>
</template>
<script>
export default {
name: 'hello',
components: {
},
data() {
return {
msg: "这是一个vue project",
colorBgConfig: [
{
color: '#2D8DFD'
},
{
color: '#FF652E'
},
{
color: '#997BFF'
},
{
color: '#01A883'
}, {
color: '#FFA522'
}
],
isActive: true,
hasError: false,
datelist: ["01.234", "12.345", "13.456", "14.567", "15"],
activeLiIndex: -1,
text: "<span>这是一个文本text</span>",
h1value2hastag: true,
attrnamevalue: "zheshiyigeH1标签",
isshowdiv1: false,
isshowdiv2: false,
radominputvalue: Math.ceil(Math.random() * 100),
isactive: true,
isaddclass1: true,
isaddclass2: false,
attrnamevalue1: "attr1",
attrnamevalue2: "attrvalue2",
inputcountvalue1: "",
inputcountvalue2: "",
showtype: true,
}
},
computed: {
value() {
return "inputvalue" + Math.ceil(Math.random() * 100)
},
inputcountedvalue() {
return this.inputcountvalue1 * this.inputcountvalue2
},
acdatelist() {
//return Object.assign([], this.datelist);
return JSON.parse(JSON.stringify(this.datelist))
},
computedh1value2hastag(arg) {
return this.h1value2hastag ? '这是一个双大括号文本text1' : '这是一个双大括号文本text2';
}
},
filters: {
valuetofixed(count, limit) {
return Math.floor(count * (Math.pow(10, limit))) / (Math.pow(10, limit))
},
unitvalue(value) {
return value + "¥"
},
},
methods: {
buttonalert1() {
// console.log("触发button元素的alert方法", "input框的值为", this.radominputvalue)
alert("触发button元素的alert1方法,input框的值为:" + this.radominputvalue)
},
buttonalert2() {
// console.log("触发button元素的alert方法", "input框的值为", this.radominputvalue)
alert("触发button元素的alert2方法,input框的值为:" + this.radominputvalue)
},
buttonalert3(arg) {
alert("触发button元素的alert3方法,参数为:" + arg)
},
randomValue: function() {
setTimeout(()=>{
this.radominputvalue = Math.ceil(Math.random() * 100);
}, 2000)
},
setlivalue(index) {
this.activeLiIndex = index
this.$set(self.datelist, index, "1234.2345")
},
inputblur() {
console.log("blur")
},
inputfocus() {
console.log("focus")
},
getrefs() {
console.log(this.$refs)
console.log(this.$refs.li1[0])
},
gorouter(rourername) {
//this.showtype = false;
//this.$router.push(rourername);
var curroute = { name: rourername }
Object.assign(curroute, { id: 10 });
this.$router.push(curroute);
},
},
watch: {
radominputvalue(newValue, oldValue) {
console.log("oldValue:", oldValue, "newValue:", newValue)
},
// datelist: {
// handler(newValue, oldValue) {
// //console.log("oldValue:", oldValue, "newValue:", newValue)
// },
// immediate: true,
// deep: true
// },
acdatelist: {
handler(newValue, oldValue) {
//console.log(oldValue, newValue)
console.log("oldValue:", oldValue, "newValue:", newValue)
}
// immediate: true,
// deep: true
// }
},
},
mounted() {
this.randomValue()
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only,only Demo-->
<style scoped lang="scss">
h1,
h2 {
font-weight: normal;
font-size: 14px;
}
.h1class{
span{
color:#f00
}
}
input {
display: inline-block;
width: 250px;
height: 32px;
line-height: 1.5;
padding: 4px 7px;
font-size: 12px;
border: 1px solid #dcdee2;
border-radius: 4px;
color: #515a6e;
background-color: #1972be;
background-image: none;
position: relative;
cursor: text;
transition: border .2s ease-in-out, background .2s ease-in-out, box-shadow .2s ease-in-out;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: block;
margin: 0 10px;
color: #5800f7;
font-size: 14px;
}
a {
user-select: none;
padding: 5px 15px 6px;
font-size: 12px;
border-radius: 4px;
background-color: #19be6b;
border-color: #19be6b;
color: #fff;
font-size: 14px;
}
ul li:hover{
color: #f00;
}
.list{
li.active{
background:var(--background-active);
}
li:hover{
background:var(--background-hover);
}
}
</style>
- 1.3 一个简单的弹框
<template>
<div>
<vxe-modal
ref="xeModal"
v-model="visible"
title="title"
:position="position"
transfer
width="width"
destroy-on-close
:show-footer="true"
:confirm-button-text="confirmButtonText"
:cancel-button-text="cancelButtonText"
@cancel="onCancelClick"
@close="onCancelClick"
@confirm="onConfirmClick"
>
<div v-if="$slots.default">
<slot></slot>
</div>
<div v-if="!$slots.default">
<vxe-textarea
v-model="content"
:autosize="autosize"
:placeholder="placeholder"
/>
</div>
</vxe-modal>
</div>
</template>
<script>
export default {
name: 'Confirm',
components: {},
props: {
visible: {
type: Boolean,
default: false
}
},
data() {
return {
position: {
top: '20%'
},
width: '40%',
title: '确认弹框',
confirmButtonText: '确定',
cancelButtonText: '取消',
autosize: {
minRows: 5,
maxRows: 10
},
placeholder: '请输入意见!',
content: ''
}
},
methods: {
onCancelClick() {
this.$emit('onCancel', this.content)
if (typeof this.cancel === 'function') {
this.cancel(this)
}
},
onConfirmClick() {
this.$emit('update:visible', false)
this.$emit('onConfirmSure', this.content)
if (typeof this.confirm === 'function') {
this.confirm(this.content, this)
}
}
},
mounted() {
},
watch: {
visible: {
handler(newval) {
},
deep: true,
immediate: true
}
}
}
</script>
<style lang='scss'>
</style>
调用示例:
<Confirm>
:visible.sync="confirmVisible"
v-if="confirmVisible"
@onConfirmSure="onConfirmSure"
</Confirm>
- 1.4 简单的弹框的实例化调用
import Vue from 'vue'
import Confirm from './Confirm.vue'
const isVNode = (node) => {
return node !== null && typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'componentOptions')
}
let id = 'confirm_0'
let ConfirmConstructor = Vue.extend(Confirm)
let instance
let instances = {}
let seed = 1
const Confirm = function (options) {
if (Vue.prototype.$isServer) return
options = options || {}
if (typeof options === 'string') {
options = {
content: options
}
}
let userOnClose = options.cancel
let userOnConfirm = options.confirm
id = 'confirm_' + seed++
options.cancel = options.cancel || function () {
Confirm.closeAndDestroy(id, userOnClose)
}
options.confirm = function (content, context) {
Confirm.confirmAndDestroy(id, userOnConfirm, content, context)
}
instance = new ConfirmConstructor({
data: options
})
instance.id = id
if (isVNode(instance.content)) {
instance.$refs.xeModal.$slots.default = [instance.content]
instance.$slots.default = [instance.content]
instance.content = null
}
instance.$mount()
document.body.appendChild(instance.$el)
instance.visible = true
instances[id] = instance
return instance
}
Confirm.closeAndDestroy = function (cid, userOnClose) {
if (typeof userOnClose === 'function') {
userOnClose(instances[cid || id])
}
document.body.removeChild(instance.$el)
instances[cid || id].$destroy()
delete instances[cid || id]
}
Confirm.confirmAndDestroy = function (cid, userOnConfirm, content, context) {
if (typeof userOnClose === 'function') {
userOnConfirm(content, context)
}
document.body.removeChild(instance.$el)
instances[cid || id].$destroy()
delete instances[cid || id]
}
export default Confirm
调用示例:
this.$Confirm({
content: '',
confirm(msg) {
console.log('confirmMsg', msg)
},
cancel() {
}
})
- 1.5 keepAlive实现
export default {
name: 'keep-alive',
// abstract: true,
props: {
include: [String, RegExp, Array],
exclude: [String, RegExp, Array],
cacheKeyType: {
type: [String],
default() {
return 'routerName' // componetName
}
},
max: [String, Number]
},
created() {
this.cache = Object.create(null)
this.keys = []
},
destroyed() {
for (const key in this.cache) {
this.pruneCacheEntry(this.cache, key, this.keys)
}
},
mounted() {
this.$watch('include', val => {
this.pruneCache(this, name => this.matches(val, name))
})
this.$watch('exclude', val => {
this.pruneCache(this, name => !this.matches(val, name))
})
},
methods: {
remove(arr, item) { // 移除某个元素
if (arr.length) {
const index = arr.indexOf(item)
if (index > -1) {
return arr.splice(index, 1)
}
}
},
isRegExp(v) { // 是否正则
return Object.prototype.toString.call(v).slice(8, -1) === 'RegExp'
},
isDef(v) { // 是不是undefined
return v !== undefined && v !== null
},
isAsyncPlaceholder(node) {
return node.isComment && node.asyncFactory
},
getFirstComponentChild(children) {
const { isDef, isAsyncPlaceholder } = this
if (Array.isArray(children)) {
for (let i = 0; i < children.length; i++) {
const c = children[i]
if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
return c
}
}
}
},
getComponentName(opts) {
return opts && (opts.Ctor.options.name || opts.tag)
},
matches(pattern, name) {
const { isRegExp } = this
if (Array.isArray(pattern)) {
return pattern.indexOf(name) > -1
} else if (typeof pattern === 'string') {
return pattern.split(',').indexOf(name) > -1
} else if (isRegExp(pattern)) {
return pattern.test(name)
}
/* istanbul ignore next */
return false
},
pruneCache(keepAliveInstance, filter) {
const { getComponentName, pruneCacheEntry } = this
const { cache, keys, _vnode } = keepAliveInstance
for (const key in cache) {
const cachedNode = cache[key]
if (cachedNode) {
const name = getComponentName(cachedNode.componentOptions)
if (name && !filter(name)) {
pruneCacheEntry(cache, key, keys, _vnode)
}
}
}
},
pruneCacheEntry(cache, key, keys, current) {
const { remove } = this
const cached = cache[key]
if (cached && (!current || cached.tag !== current.tag)) {
cached.componentInstance.$destroy()
}
cache[key] = null
remove(keys, key)
},
destroy(key) {
this.pruneCacheEntry(this.cache, key, this.keys)
},
update(key) {
const { cache, keys, pruneCacheEntry } = this
const slot = this.$slots.default
const vnode = this.getFirstComponentChild(slot)
pruneCacheEntry(this.cache, key, this.keys)
keys.push(key)
cache[key] = vnode
}
},
render() {
const { matches, getComponentName, pruneCacheEntry, remove, cache, keys } = this
const slot = this.$slots.default
const vnode = this.getFirstComponentChild(slot)
const componentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name = this.cacheKeyType === 'routerName' ? this.$route.name : getComponentName(componentOptions)
const { include, exclude } = this
if (
(include && (!name || !matches(include, name))) ||
(exclude && name && matches(exclude, name))
) {
return vnode
}
let ifCache = this.cacheKeyType === 'routerName' ? this.$route.meta.keepAlive : true
let key = vnode.key == null
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key
if (this.cacheKeyType === 'routerName') {
key = this.$route.name
}
if (ifCache) {
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
}
- 1.6 递归组件
一种自己调用自己的组件,至于有哪些应用,自己悟吧!
- 1.7 vueX状态管理 和 模块化
vueX使用说明
1、this.$store : 我们可以通过 this.$store 在vue的组件中获取vuex的实例。
2、State : vuex中的数据源,我们可以通过 this.$store.state 获取我们在vuex中声明的全局变量的值。
3、Getter: 相当于vue中的computed , 及 计算属性, 可以用于监听、计算 state中的值的变化
4、Mutation: vuex中去操作数据的方法 (只能同步执行)
5、Action: 用来操作 Mutation 的动作 , 他不能直接去操作数据源,但可以把mutation变为异步的
6、Module: 模块化,当你的应用足够大的时候,你可以把你的vuex分成多个子模块
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
// 在state中去声明全局变量,可以通过 this.$store.state 访问
state: {
count: 0
},
// 在getters中声明state中变量的计算函数,缓存计算后的数据, 通过 this.$store.getters 调用
getters: {
// 接受state作为参数,每次 count发生变化时 , 都会被调用
consoleCount: state => {
console.log('the state count : ' + state.count);
return state.count;
}
},
// 只能执行同步方法,不要去执行异步方法 通过 this.$store.commit 方法去调用
mutations: {
// 改变state状态的方法,不建议直接通过
// this.$store.state.? = ?的方式改变state中的状态
addCount: state => {
++state.count;
},
// 自定义改变state初始值的方法,mutations的第一个参数即为state对象,并且可以向mutation传入额外的参数(变量或对象);
addNumCount: (state, n) => {
state.count+=n;
},
},
// 借助actions的手去 执行 mutations , 通过 this.$store.dispatch 的方式调用
// 可以用来执行异步操作,可以跟踪异步数据状态变化
actions: {
// 调用 mutation
addCount: context => {
context.commit('addCount');
},
addNumCount: (context, n) => {
context.commit('addNumCount', n);
}
}
})
我们在代码中分别注册了,state、getters、mutations、actions。
这样我们就可以在任何一个 component中通过this.store.dispatch(′addNumCount′,5);或者 this.$store.dispatch('addCount'); 去触发actions操作来改变state中的值。
应用示例:
vueX定义
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const state = {
loading: false,
userInfo: {
phone: 123456789000000,
account: "Titans",
}, //用户信息
login: false, //是否登录
shopList:[{
id: 1,
name: '兰博基尼',
price: 10000000
},{
id: 2,
name: '奥迪',
price: 1000000
}],
};
const getters = { //实时监听state值的变化(最新状态)
isloading(state) { //承载变化的login的值. //.$store.getters.isloading
return state.loading
},
islogin(state) {
return state.login
},
getuserInfo(state){
return state.userInfo
}
};
const mutations = {
setloading(state, isshow) { //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象);
state.loading = isshow;
},
setlogin(state, islogin) { //this.$store.commit("setlogin", true)
state.login = islogin;
},
setuserInfo(state, userInfoobj){
state.userInfo=userInfoobj
}
};
const actions = {
asyncsetoading: (context,loadingstatus) => {//this.$store.dispatch("asyncsetoading", false)
context.commit('setloading',loadingstatus);
},
};
const modulea = {
namespaced: true,
state: {
usera: "taitan",
shopList: [{
id: 1,
name: '兰博基尼',
price: 10
}, {
id: 2,
name: '五菱宏光',
price: 99999
}],
},
mutations: {
setusera(state,name) {
state.usera = name
}
},
actions: {
asyncsetusera:(context, name)=> {
context.commit("setusera", name)
}
},
getters: {
getusera(state) {
return state.modulea.usera
}
}
}
export default new Vuex.Store({
state,
getters,
mutations,
actions,
modules: { modulea
}
});
页面调用:
<template>
<div class="vuexstore">
<h1>{{ msg }}</h1>
<br>
<Button type="primary" @click="goBack">goBack one step</Button>
<br>
<br>
<Button type="primary" @click="getstate">getstate</Button>
<Button type="primary" @click="setstate">setstate</Button>
<Button type="primary" @click="setstateasync">setstateasync</Button>
<Button type="primary" @click="getmapvuex">getmapvuex</Button>
</div>
</template>
<script>
import { mapGetters, mapMutations, mapState, mapActions } from 'vuex'
export default {
name: 'Vuexstore',
components: {
},
data() {
return {
msg: "以下是一个vue project组件VUEX",
}
},
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'getuserInfo',
'islogin',
'isloading'
// ...
]),
// getuserInfo(){
// return this.$store.getters.getuserInfo
// },
...mapState([
// 映射 this.shopList为 store.state.shopList
'shopList'
]),
...mapState('modulea', ['usera'])
},
methods: {
goBack() {
window.history.length > 1 ?
this.$router.go(-1) :
this.$router.push('/')
},
getstate() {
alert(this.getuserInfo)
alert(this.$store.state.userInfo.phone)
this.$store.state.userInfo.phone=12344566
alert(this.$store.state.modulea.usera)
},
setstate() {
this.$store.commit("setlogin", true)
alert(this.$store.getters.islogin)
//this.setusera("taitanmodul");
this.$store.commit('modulea/setusera',"taitanmodul")
alert(this.$store.state.modulea.usera)
alert(this.$store.getters['modulea/getusera'])
this.setusera("taitanmodulmap");
alert(this.$store.state.modulea.usera)
},
setstateasync() {
this.$store.dispatch("asyncsetoading", false)
alert(this.$store.getters.isloading)
this.$store.dispatch('modulea/asyncsetusera',"taitanmodulceshi")
alert(this.$store.getters['modulea/getusera'])
},
getmapvuex() {
console.log(this.getuserInfo);
console.log(this.shopList);
this.setlogin("mapfalse")
console.log(this.$store.getters.islogin);
this.setuserInfo({
phone: 19993170150,
account: "Titans",
})
console.log(this.$store.state.userInfo.phone);
this.asyncsetoading("已经加载")
console.log(this.$store.getters.isloading);
console.log(this.usera);
},
...mapMutations('modulea',[
'setusera',
]),
...mapMutations([
'setlogin', // 将 `this.setlogin(true)` 映射为 `this.$store.commit('setlogin',true)`
// `mapMutations` 也支持载荷:
'setuserInfo' // 将 `this.setuserInfo(info)` 映射为 `this.$store.commit('setuserInfo', info)`
]),
...mapActions({
asyncsetoading: 'asyncsetoading' // 将 `this.asyncsetoading(false)` 映射为 `this.$store.dispatch("asyncsetoading", false)`
})
},
mounted() {
},
}
</script>
- 1.8 可保持复用菜单路由
实现方法
addRoute() And <KeepAlive>
<KeepAlive ref="keepAlive">
<router-view v-if="$route.meta.keepAlive && ifrouteractive" :key="$route.name" />
</KeepAlive>
<router-view v-if="!$route.meta.keepAlive && ifrouteractive" :key="$route.name" />
this.$refs.keepAlive.destroy(this.$route.name)
路由和组件的常用两种懒加载方式:
1、vue异步组件实现路由懒加载
component:resolve=>(['需要加载的路由的地址',resolve])
2、es提出的import(推荐使用这种方式)
const HelloWorld = ()=>import('需要加载的模块地址')
npm run build后会新增路由数量与之加载相匹配的.js文件,在切到相应路由或组件时动态加载这个文件。
// 这两条路由被打包在相同的块中,访问任一路由都会延迟加载该路由组件
const OtherMassivePage = r => require.ensure([], () => r(require('./routes/OtherMassivePage.vue')), 'big-pages')
const WeightLossPage = r => require.ensure([], () => r(require('./routes/WeightLossPage.vue')), 'big-pages')
尤其需要注意,并请思考多次 import 同一个 的全局提升,导入以及导出的提升,有关此请移步
JavaScript大总结es6++(next)部分(持续完善ing)https://juejin.cn/post/6986657782720266248
const data={a:123} // 复杂数据类型
export default data
A组件导入
import data from 'url/*/*/*/*'
dada(){
return {
dataa:dataa
}
},
methods:{
fn(){
this.dataa.a=234
}
}
B组件也像A组件这么导入和调用,如果A组件先掉用,B组件再掉用,请问B组件导入进来的DataA是A组件修改后的值还是定义导出所写的那个值?
- 1.9 render函数
vue render函数说明
render: (h, params) => {
var vm = this;
return h('Input', {
attrs: {
value: params.row.age,
readonly: params.row.status == 2 ? false : true,
class: params.row.status == 2 ? "border ivu-input" : "noborder ivu-input",
},
on: {
input(val) {
这里用的是iview Input组件,input事件的返回值是改变后的值,若要调用event,需直接调用:var event=window.event;
若直接用原生的input标签,input事件的返回值是event,改编后的值用event.target.value;
//值改变时
//将渲染后的值重新赋值给单元格值;
params.row.age = val;
vm.data8[params.index] = params.row;
}
}
})
}
上面是渲染表格的某一列的一个例子,当需要分情况渲染不同元素时,可以如下格式去写:
render: (h, params) => {
return h('div', [
h('Button', {
style: {
display: params.row.status == 0 ? "inline-block" : "none",
marginRight: '5px'
},
on: {
click: () => {
this.edit(params.index)
}
}
}, 'edit'),
h('Button', {
style: {
display: params.row.status == 2 ? "inline-block" : "none",
marginRight: '5px'
},
on: {
click: () => {
this.endedit(params.index)
}
}
}, 'endedit')
]);
}
}
h相当于createElement,为一个回调函数,h的第二个参数为一个对象,也可以为一个数组,每个值又为一个对象,当然也可以嵌套多层标签,支持的所有属性如下(以下所有的属性值都支持表达式赋值)
{
// 和`v-bind:class`一样的 API
'class': {
foo: true,
bar: false
},
// 和`v-bind:style`一样的 API
style: {
color: 'red',
fontSize: '14px'
},
// 正常的 HTML 特性
attrs: {
id: 'foo'
},
// 组件 props
props: {
myProp: 'bar'
},
// DOM 属性
domProps: {
innerHTML: 'baz'
},
// 事件监听器基于 `on`
// 所以不再支持如 `v-on:keyup.enter` 修饰器
// 需要手动匹配 keyCode。
on: {
click: this.clickHandler
},
// 仅对于组件,用于监听原生事件,而不是组件内部使用 `vm.$emit` 触发的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定义指令。注意事项:不能对绑定的旧值设值
// Vue 会为您持续追踪
directives: [
{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// Scoped slots in the form of
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果组件是其他组件的子组件,需为插槽指定名称
slot: 'name-of-slot',
// 其他特殊顶层属性
key: 'myKey',
ref: 'myRef'
}
2 深入组件
- 2.1 动画 transition
- 2.2 插槽,scopeSlots
- 2.3 render函数
3 全局api