vue项目之仿头条

初始化

yarn add vue-router@3.5.3

yarn add vuex@3.6.2

装router和store

Git

​git remote remove origin
git remote add origin https://gitee.com/nikki-u/headline.git
git push -u origin "master"

如果远程仓库被占用

git remote remove origin
git remote add XXX//路径
git push XXX//分支

iconfont

资源管理-我的项目-新建项目-头条

1 创建项目--2fontclass--3添加图片--4去掉颜色提交--5生成在线链接--

6复制css--7粘贴进 新建style/icon.css--8在main.js中引进--使用

vant导入所有组件(项目需求大导入所有组件,其他推荐导入部分)

1、yarn add vant@2.12.24

2、引入全局main.js

import Vant from 'vant';
import 'vant/lib/index.css';
​
Vue.use(Vant);

3、直接使用

axios

1、yarn add axios

2、utils/request.js

import axios from "axios";
const request=axios.create({
    baseURL:"http://toutiao.itheima.net/"
})
​
export default request

rem适配

1、

yarn add amfe-flexible

2、main.js

import 'amfe-flexible'

3、postcss-pxtorem将px转换为rem

yarn add postcss postcss-pxtorem@5.1.1 

4、.postcssrc.js

module.exports = {
  plugins: {
    'autoprefixer': {
      browsers: ['Android >= 4.0', 'iOS >= 8']
    },
    'postcss-pxtorem': {
      //rootValue: 37.5,
      rootValue({ file }) {
        return file.indexOf('vant') !== -1 ? 37.5 : 75
      },//用于两个设计稿,vant设计稿和产品设计稿
      propList: ['*']
    }
  }
}

登录注册

1、切换分支login

2、设置路由

const router = new VueRouter({
    routes: [
        { path: '/', redirect: '/layout/home' },
        { path: '/login', component: () => import('@/views/login') },
        { path: '/search', component: () => import('@/views/search') },
        { path: '/profile', component: () => import('@/views/user-profile') },
        { path: '/article/:articleId', 
            component: () => import('@/views/article') ,props:true},
        {
            path: '/layout', component: () => import('@/views/layout'), children: [
                { path: 'home', component: () => import('@/views/home') },
                { path: 'my', component: () => import('@/views/my') },
                { path: 'video', component: () => import('@/views/video') },
                { path: 'qa', component: () => import('@/views/qa') },
            ]
        },
    ]
})

3、使用vant组件

navbar导航栏

form表单

field输入框

button按钮

4、ui布局

样式

5、styles/index.less写入样式

6、

yarn add less less-loader@5.0.0

7、main.js引入样式

index.vue

8、登录图标和验证码template

9、clearable

10、登录

11、this.$toast.success("登录成功");

12、加载

13、表单校验

:rules="userFormRules.mobile"
data、、
userFormRules: {
    mobile: [
        {required:true,message:'不能为空'},
        {pattern:/^1[3|5|6|7|8]\d{9}$/,message:'电话格式错误'},
    ],
    code:  [
        {required:true,message:'不能为空'},
        {pattern:/^\d{6}$/,message:'验证码格式错误'},
    ],
},

14、点击发送验证码

native-type="button"
await this.$refs.loginForm.validate("mobile");

验证手机号+发送验证码

15、倒计时

16、获取验证码

查询参数params:{}+get

请求参数data:{}+post

路径参数/:参数${}

17、保存到vuex和本地

18、封装storage.js

19、上传到git  git部分指令

git add .

git commit -m ''

git checkout master

git merge login

git branch -d login

git push

日常工作如何使用git

git clone从无到有

git pull早上远程拉取代码

git pull晚上远程拉取代码

git push每次push之前先git pull

个人中心

1、创建路由

layout

-home

-qa

-video

-my

2、路由懒加载 利用回调函数导入组件()=>import '@/...'

提高性能 缩短首屏加载时间

3、开启路由route

4、登录ui页面

5、添加导航栏

6、v-if v-else登录未登录切换

7、获取用户信息

8、渲染

9、退出登录

10、提示框toast

11、axios请求拦截器

axios里面有两个拦截器

请求拦截器

响应拦截器

12、优化 判断如果没有请求就返回

13、axios响应拦截器

文章列表

/deep/

不加的情况下会在类名后加上属性选择器 如果加上/deep/就不会改变名字

  //1. 可能是因为权重优先级
  //2. 没有属性 (摸一下)
<style lang='less' scoped>
.layout-container {
  .text {
    color: blueviolet 
  }
}
</style>
'>>>'

<style lang='css' scoped>
.layout-container >>> .text{
  color: blueviolet!important
}
</style>

1、渲染ui结构

2、导航栏

3、处理汉堡按钮

4、获取展示频道列表

5、channel.js

6、ArticleList组件

7、组件里list数据

8、article.js关于文章获取列表

9、动态加载数据

10、添加加载失败

方案一:抛出错误

方案二:padding-bottom断网

11、下拉刷新

12、刷新成功文本

13、文章列表项组件

14、图片

15、处理相对时间

yarn add  dayjs

频道列表-汉堡按钮

1、创建channel分支

2、popup弹出层

3、channel-edit.vue

4、频道渲染

5、加号、删除图标

6、展示我的频道

7、获取所有频道

8、筛选没有的频道

方法一:使用filter、some/filter、find

方法二:import _ from 'lodash'

recommendChannels() {
    return _.differenceWith(this.allChannels, this.myChannels, _.isEqual);
   }

9、处理高亮

10、添加到我的频道

12、删除我的频道

13、编辑频道

14、数据持久化

15、删除频道到接口

16、添加频道到接口

文章搜索

1、设置路由

2、渲染ui结构

3、封装三个模块

4、判断显示组件

5、失焦隐藏搜索结果

6、联想搜索监听输入框内容变化

immediate:true

7、获取联想建议

8、防抖

yarn add lodash

import { debounce } from "lodash"//局部防抖

handler: debounce(function (val) {
    this.loadSearchSuggestion(val)
}, 1000)

9、处理高亮文字

搜索结果

10、处理搜索结果

11、请求数据

12、处理失败

13、固定顶部

14、添加历史记录

15、设置清除事件

16、去重

onSearch(val) {
      if(!this.searchText){
        return
      }
      this.searchText = val;
      // 方法一
      // let index=this.searchHistories.indexOf(val)
      // if(index>=0){
      //   this.searchHistories.splice(index,1)
      // }
      // this.searchHistories.unshift(val)
      // 方法二
      // this.searchHistories.unshift(val)
      // this.searchHistories=[...new Set(this.searchHistories)]
      // 方法三
      this.searchHistories.unshift(val)
      this.searchHistories=_.uniq(this.searchHistories)
​
      this.isResult = true;
      //console.log(this.isResult);
    },
    onCancel() {
      this.$router.back();
    },

17、点击删除历史记录

18、持久化

文章详情

1、创建组件

2、设置路由

3、to设置跳转

//在路由里面写props:true     this.$route.params.articleId=>this.articleId
  console.log(this.$route.params.articleId);
  console.log(this.articleId);

4、根据文章id获取对应文章

5、修改样式07笔记

https://github.com/sindresorhus/github-markdown-css/blob/main/github-markdown.css

 

@click-left="$router.back()"

如果没有图片,可以设置

<meta name="referrer" content="no-referrer" />

6、图片预览

setTimeout(() => {
  this.ImagePre();
}, 100);
    ImagePre() {
      let contentEl = this.$refs.contentRef;
      let allImages = contentEl.querySelectorAll("img");
      // console.log(allImages);
      let images = [];
      allImages.forEach((element, index) => {
        // console.log(element);
        // console.log(index);
        images.push(element.src);
        // console.log(images);
        element.onclick = function () {
          ImagePreview({
            images,
            // 预览图片的起始位置
            startPosition: index,
          });
        };
      });
    },

7、关注用户

8、删除用户

9、comment-list

10、获取评论列表

11、获取总评论

$event是出现在vue中 如果传了参数$event就是参数 如果没有传参 代表事件

@on-success='totalCount=$event'

12、comment-item

13、喜欢

14、comment-post

15、发布文章评论

16、回复成功文章

17、回复评论

18、评论回复

19、comment-reply

20、获取评论

21、获取评论的评论

22、comment子传父传父传子

23、隐藏评论的评论的回复

24、发布回复

用户页面

1、设置路由

2、渲染用户ui页面

3、获取用户信息

4、修改昵称

5、封装user-name组件

6、设置关闭按钮

7、修改昵称接口(注意传参数)

8、右键确定

9、回显

10、编辑性别

11、v-model包含哪两个指令 v-bind v-on

<div>
  <!-- 2、合并写法 -->
  <input type="text" v-model="name">
  <!-- 3、拆分语法 -->
  <br>
  <input type="text"
 :value="message"
 @input="message=$event.target.value">
  <input type="checkbox"
 :checked='myChecked'
 @change="myChecked=$event.target.checked">
</div>
message: this.name,
myChecked:true

         11.4、高级用法

         11.5、.sync用法

12、改变性别

13、van-picker

14、发起改变请求

15、改变生日

编辑头像

1、隐藏input框 设置头像

2、获取元素

3、添加弹窗

4、添加裁切工具

yarn add cropperjs
import 'cropperjs/dist/cropper.css'
import Cropper from 'cropperjs'
//在mounted里面写入代码  获取cropper实例
const image = this.$refs.img;
this.cropper = new Cropper(image, {
      viewMode: 1, // 只能在裁剪的图片范围内移动
      dragMode: 'move', // 画布和图片都可以移动
      aspectRatio: 1, // 裁剪区默认正方形
      autoCropArea: 1, // 自动调整裁剪图片
      cropBoxMovable: false, // 禁止裁剪区移动
      cropBoxResizable: false, // 禁止裁剪区缩放
      background: false // 关闭默认背景
    })

在方法里获取裁剪区域

confirm () {
// console.log(this.cropper.getData())
// blob base64 baseUrl      this.cropper.getCroppedCanvas().toBlob(blob => {
        console.log(blob)
  })
}

5、设置请求接口

6、传递数据

// 创建一个空formdata实例:用来传递文件数据
let fd = new FormData();
fd.append("photo", blob);
// 打印fd
// fd.forEach((v,k)=>{
//     console.log(k,v);
// })
let res = await updateUserAvatar(fd);//请求
// console.log(res.data.data.photo);
this.$emit("close");
this.$emit("update:img", res.data.data.photo);

token失效问题

token

refresh_token

request.interceptors.response.use(
  response => {
    // 成功的
    return response
  },
  async error => {
    // 对响应错误做点什么

    //1 token 问题
    // 失效 ?  没有token ?
    if (error.response.status === 401) {
      //2. 判断 refresh_token 有没有
      let user = store.state.user
      // 2.1 没有 refresh_token
      if (!user.refresh_token) {
        // 提示
        Toast.fail(error.response.data.message)
        // 跳转
        router.push('/login')
        return
      }

      // 2.2 有 refresh_token => 换取 新的token
      try {
        let res = await axios({
          method: 'put',
          url: 'http://toutiao.itheima.net/v1_0/authorizations',
          headers: {
            Authorization: `Bearer ${user.refresh_token}`,
          },
        })

        console.log(res.data)

        // 3 替换本地的token
        store.commit('setUser', {
          token: res.data.data.token,
          refresh_token: user.refresh_token,
        })

        //4. 把之前 失效的token `请求` ==> 改为用最新的token `请求` 替代 => 继续请求
        return request(error.config)
      } catch (error) {
        // refresh_token  有值 , 但是过期了, 请求失败
        router.push('/login')
      }
    }

    return Promise.reject(error)
  }
)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue黑马头条项目的难点主要包括以下几个方面: 1. 数据流管理:在Vue黑马头条项目中,需要管理大量的数据,包括用户信息、新闻内容、评论等。如何有效地处理并管理这些数据,确保数据的正确性和一致性是一个难点。可以使用Vuex来进行全局的数据管理,并通过状态管理模式来统一管理数据的流动和变化。 2. 组件交互与通信:Vue黑马头条项目中使用了大量的组件,组件之间的交互与通信是其中一个难点。组件之间需要进行数据的传递、事件的派发与监听,如何高效地组织和管理这些组件之间的交互,提高项目的可维护性和扩展性是一个挑战。 3. 页面布局和样式:Vue黑马头条项目的页面比较复杂,需要考虑到不同屏幕尺寸的适配和响应式布局。同时,页面中的样式设计也需要符合美观和用户体验的要求。如何在保持页面布局的灵活性和可扩展性的同时,确保页面样式的一致性和用户友好性也是一个难点。 4. 请求与响应处理:Vue黑马头条项目需要与后台进行数据交互,包括获取新闻内容、发布评论等。在请求与响应处理中,需要考虑到网络请求的错误处理、数据的缓存和异步操作的管理等问题,确保用户在使用过程中的流畅性和体验。 5. 性能优化:Vue黑马头条项目中的数据量较大,页面频繁地进行数据的渲染和更新,对页面的性能和响应速度提出了要求。如何通过合理的数据缓存、懒加载、组件按需加载等方式进行性能优化,提高项目的执行效率和用户体验,是一个需要解决的难题。 通过了解和解决这些难点,可以更好地设计和实现Vue黑马头条项目,提高项目的开发效率和用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值