vue3项目实战---知乎日报----收藏页

目录

vuex

网络请求

列表页收藏功能

页面如何获取vuex的值vue3 vs vue2

computed


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

  1. 计算属性有缓存,计算属性会把函数执行一次,把结果存起来,依赖的值改变,会重新赋值。
  2. 支持缓存,只有当它所依赖的响应式数据发生改变时,才会重新进行计算
  3. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
  4. .computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
  5. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
  6. 如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值