目录
vuex
import { createStore } from "vuex";
import { CheckLogin, UserLnfo, StoreList } from '../api/index'
const store = createStore({
state: {
isLogin: null,
info: null,
storeList: null
},
mutations: {
changeIsLogin(state, bool) {
state.isLogin = bool
},
changeInfo(state, payload) {
state.info = payload
},
changeStoreList(state, payload) {
state.info = payload
},
removeStoreList(state, id) {
if (store.storeList == null) return
state.storeList = state.storeList.filter(item => {
return +item.id !== id
})
}
},
actions: {
async changeIsLoginAsync({ commit }) {
let bool = false
let { code } = await CheckLogin()
if (code == 0) bool = true
commit('changeIsLogin', bool)
},
async changeInfoAstnc({ commit }) {
let { code, data } = await UserLnfo()
if (code == 0) {
commit('changeInfo', data)
}
},
async changeStoreAsync({ commit }) {
let { code, data } = await StoreList()
if (code !== 0) data = []
commit('changeStoreList', data)
}
},
})
export default store
网络请求
//获取收藏列表
export const StoreList = () => {
return axios.get('/api/store_list ')
}
//删除收藏
export const StoreRemove = id => {
return axios.get('/api/store_remove', {
params: {
id
}
})
}
//收藏
export const storea = (news) => {
return axios.post('/api/store ', {
news
})
}
列表页收藏功能
some 只要有一项为true就为true
dispatc派发返回一个promise实例
vue3 //如果想获取计算属性的值应该.value
<template>
<van-skeleton title :row="5" v-if="NewsInfo === null" />
<div class="content" v-html="NewsInfo.body" v-else></div>
<div class="nav-box">
<van-icon name="arrow-left" @click="handle" />
<van-icon name="comment-o" :badge="comments" />
<van-icon name="good-job-o" :badge="popularity" />
<van-icon
name="star-o"
:color="isStore ? '1989fa' : '#000'"
@click="storeHandle"
/>
<van-icon name="share-o" color="#ccc" />
</div>
</template>
<script>
import { useRouter, useRoute } from "vue-router";
import {
reactive,
toRefs,
onBeforeMount,
onBeforeUnmount,
onUpdated,
computed,
} from "vue";
import { Toast } from "vant";
import { NewsInfo, StoryExtra, storea } from "../api/index";
import { useStore } from "vuex";
export default {
name: "Detail",
setup() {
let state = reactive({
comments: 0, //评论总数
popularity: 0, //点赞数
NewsInfo: null,
});
//路由实例对象控制路由跳转
const router = useRouter();
//路由信息对象,获取路径参数
const route = useRoute();
//获取公共状态
const store = useStore();
//点击跳转返回上一级
const handle = () => {
router.back();
};
//获取数据
onBeforeMount(async () => {
let id = route.params.id;
let result = await NewsInfo(id);
state.NewsInfo = result;
let { comments, popularity } = await StoryExtra(id);
state.comments = comments;
state.popularity = popularity;
//动态创建css
let link = document.createElement("link");
link.id = "link";
link.rel = "stylesheet";
link.href = state.NewsInfo.css[0];
document.head.append(link);
});
//数据更新后,可以获取到dom 追加图片
onUpdated(() => {
let img = document.querySelector(".img-place-holder");
if (img && img.innerHTML.trim() == "") {
img.innerHTML += `<img src="${state.NewsInfo.image}" alt="">`;
}
});
//移除link标签避免样式冲突
onBeforeUnmount(() => {
let link = document.getElementById("link");
if (!link) return;
document.head.removeChild(link);
});
/* 收藏逻辑 */
// 判断是否收藏,some只要有一项符合就为true,
let isStore = computed(() => {
let { isLogin, storeList } = store.state;
if (isLogin) {
if (!Array.isArray(storeList)) storeList = [];
return storeList.some((item) => {
return item.news.id === route.params.id;
});
}
return false;
});
//同步收藏(每一次派发都返回一个promise实例)
onBeforeMount(async () => {
//只有登陆了才同步收藏列表
if (store.state.isLogin === null) {
await store.dispatch("changeIsLoginAsync");
}
if (store.state.isLogin) {
if (store.state.info === null) store.dispatch("changeInfoAstnc");
if (store.state.storeList == null) store.dispatch("changeStoreAsync");
}
});
//收藏按钮
const storeHandle = async () => {
if (!store.state.isLogin) {
Toast("小主,请先登录哦~");
router.push("/login");
return;
}
//如果想获取计算属性的值应该.value
if (isStore.value) return true;
let { code } = await storea(route.params.id);
if (code != 0) {
Toast("小主,很遗憾收藏失败");
return;
}
Toast("小主,收藏成功啦~");
store.dispatch("changeStoreAsync");
};
return {
...toRefs(state),
handle,
isStore,
storeHandle,
};
},
};
</script>
<style lang="less" scoped>
.content {
background: #fff;
padding-bottom: 50px;
margin: 0;
/deep/.img-place-holder {
overflow: hidden;
height: 375px;
img {
width: 100%;
min-height: 100%;
margin: 0;
}
}
}
.nav-box {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
background: #f4f4f4;
height: 50px;
padding: 0 15px;
.van-icon:nth-child(1) {
position: relative;
&::after {
position: absolute;
content: "";
width: 1px;
top: -10%;
right: -15px;
height: 120%;
background: #d5d5d5;
}
}
/deep/.van-badge {
background-color: transparent;
border: none;
color: #000;
right: -5px;
}
}
.van-skeleton {
padding: 30px 15px;
}
</style>
页面如何获取vuex的值vue3 vs vue2
vue2
都需要依赖vue的computed计算属性来实现。
因为:在vue的实际应用中,computed属性可以在输出前,对data中的值进行改变,因此,我们就是利用computed的这一特性,在组件中获取vuex的state对象中的属性。
1.在插值表达式{{ }}中使用state的状态属性count时,写法是:{{$store.state.count}};
2.在computed中定义一个方法,并return出state对象中的属性及其状态:
3. 利用vuex的mapState方法来获取vuex的state对象中属性,它有两种写法:
import { mapState } from 'vuex'
然后在computed中这样写:
computed:{
...mapState({
count:state => state.count //使用ES6的箭头函数来给count赋值
})
}
(mapState中用数组的形式获取):
import { mapState } from 'vuex'
然后在computed中这样写:
computed:{
...mapState(['count'])
}
vue3
mport { useStore } from "vuex";
import { defineComponent, toRefs } from "vue";
export default defineComponent({
setup() {
const store = useStore();
// state
const { age, sex, name } = toRefs(store.state);
// mutations
store.commit("changeName", "newName");
// actions
store.dispatch("changeNameAsync", "newName2");
// getters
const fullInfo = computed(() => store.getters.fullInfo);
return {
age,
sex,
name,
fullInfo,
};
},
});
computed
- 计算属性有缓存,计算属性会把函数执行一次,把结果存起来,依赖的值改变,会重新赋值。
- 支持缓存,只有当它所依赖的响应式数据发生改变时,才会重新进行计算
- 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
- .computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
- 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
- 如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。