20230726----重返学习-vue3项目实战-知乎日报第3天-TS-简历

day-121-one-hundred-and-twenty-one-20230726-vue3项目实战-知乎日报第3天-TS-简历

vue3项目实战-知乎日报第3天

封装按钮组件

jsx函数式组件

  1. 只能做静态页面,内部没有方法让它自动更新。

封装第三方按钮-非计算属性版

  1. 封装第三方按钮-不使用计算属性
  • src/components/ButtonAgain.jsx
import { Button } from 'vant'
import { ref, useAttrs, useSlots } from 'vue'

// 把传递的属性,去除特殊的,其余的都赋值给Vant内部的组件
const filter = (attrs) => {
  let props = {}
  Reflect.ownKeys(attrs).forEach((key) => {
    if (key === 'loading' || key === 'onClick') return
    props[key] = attrs[key]
  })
  return props
}

const ButtonAgain = {
  inheritAttrs: false,
  setup() {
    const attrs = useAttrs(),
      slots = useSlots()

    // 自己控制loading效果
    const loading = ref(false)
    const handle = async (ev) => {
      loading.value = true
      try {
        await attrs.onClick(ev)
      } catch (_) {}
      loading.value = false
    }

    console.log(`1- 非计算属性版`)
    return () => {
    console.log(`2- 非计算属性版`)
      let props = filter(useAttrs())
      return (
        
      )
    }
  }
}
export default ButtonAgain

封装第三方按钮计算属性版

  1. 封装第三方按钮-使用计算属性。
  • src/components/ButtonAgain.jsx
import { Button } from 'vant'
import { ref, useAttrs, useSlots, computed } from 'vue'

const ButtonAgain = {
  inheritAttrs: false,
  setup() {
    const attrs = useAttrs(),
      slots = useSlots()
    const props = computed(() => {
      let attrs = useAttrs()
      let props = {}
      Reflect.ownKeys(attrs).forEach((key) => {
        if (key === 'loading' || key === 'onClick') return
        props[key] = attrs[key]
      })
      return props
    })

    // 自己控制loading效果
    const loading = ref(false)
    const handle = async (ev) => {
      loading.value = true
      try {
        await attrs.onClick(ev)
      } catch (_) {}
      loading.value = false
    }

    console.log(`计算属性版`)

    return () => {
      return (
        
      )
    }
  }
}
export default ButtonAgain

函数式调用组件的处理优化

  • src/components/overlay/Index.vue



  • src/components/overlay/index.js
import { createVNode, render } from 'vue'
import Index from './Index.vue'

export default function showOverlayLoading() {
  // 创建虚拟DOM。
  let vnode = createVNode(Index)
  // 渲染虚拟DOM
  // console.log(`vnode-->`, vnode);

  const frag = document.createDocumentFragment()
  render(vnode, frag)
  document.body.appendChild(vnode.el, frag)

  return function hiddenOverlayLoading() {
    if (vnode?.el) {
      document.body.removeChild(vnode.el)
      vnode = null
    }
    // render(null, frag)
  }
}

登录页






提交表单信息

  1. 对表单进行校验。
  2. 发送请求。
  3. 登录成功:存储token、进行提示。
  4. 获取登录者信息、进行页面的跳转。

获取登录者信息

  1. 从服务器获取登录者信息。
    • 一般是在pinia中创建出来的。
      • src/stores/base.js

        import { defineStore } from 'pinia'
        import { ref } from 'vue'
        import API from '@/api'
        
        const useBaseStore = defineStore('base', () => {
          // 定义公共状态。
          const profile = ref(null)
        
          // 修改公共状态。
          // 
          const queryProfile = async () => {
            let info = null
            try {
              let { code, data } = await API.userInfo()
              if (code === 0) {
                info = data
                profile.value = info
              }
            } catch (error) {
              console.log(`error:-->`, error)
            }
            return info
          }
          // 暴露给外面用。
          return {
            profile,
            queryProfile
          }
        })
        export default useBaseStore
        

登录态校验

  • src/router/index.js

    import { createRouter, createWebHashHistory } from 'vue-router'
    import routes from './routes'
    import useBaseStore from '@/stores/base'
    import { showFailToast } from 'vant'
    
    
    const router = createRouter({
      history: createWebHashHistory(),
      routes
    })
    
    // 全局前置守卫:登录态校验
    const checkList = ['/person', '/store', '/update']//用于判断那些页面需要登录态校验。
    router.beforeEach(async (to, from, next) => {
      const base = useBaseStore()//用于拿到个人信息。
      let profile = base.profile
      if (checkList.includes(to.path) && !profile?.value) {
        let info = await base.queryProfile()
        if (!info) {
          // 真的没登录过。
          showFailToast('您还未登录,请先登录')
          next({
            path: '/login',
            query: {
              target: to.fullPath
            }
          })
          return
        }
      }
    
      next()
    })
    // 全局后置守卫
    router.beforeEach((to, from) => {
    
    })
    export default router
    
  • src/views/Login.vue

    
    
    
    
    
    
    
  • 会有一个问题-路由错乱的问题。

登录页的跳转

  1. 让登录页中可以直接跳转回来源页面。
  • src/views/Login.vue




返回上一页功能

  1. 单独做一个组件,专门来处理返回逻辑。
  • src/components/NavBack.vue





函数式调用组件的封装

  1. 先写一个主组件。主组件可以用模板组件,也可以用jsx组件

    • src/components/overlay/Index.vue 模板组件

      
      
      
      
    • src/App.vue 在根视图中先看模板组件效果

      
      
      
      
  2. 写一个js函数,用于在全局中渲染组件和移除主组件。

    • src/components/overlay/Index.vue 主组件

      
      
      
      
    • src/components/overlay/index.js 在js文件中用js方式来在全局中插件入调用。

      import { createVNode, render } from 'vue'
      import Index from './Index.vue'
      
      export default function showOverlayLoading() {
        // 创建虚拟DOM。
        const vnode = createVNode(Index)
        // 渲染虚拟DOM
        console.log(`vnode-->`, vnode);
      
        const frag = document.createDocumentFragment()
        render(vnode, frag)
        document.body.appendChild(vnode.el, frag)
      
        return function hiddenOverlayLoading() {
          render(null, frag)
        }
      }
      
    • src/App.vue 根组件中尝试调用

      
      
      
      
      
      

路由中进行loading

  • src/components/overlay/Index.vue 全局loading模板组件



  • src/components/overlay/index.js 函数式调用全局loading模板组件的方法
import { createVNode, render } from 'vue'
import Index from './Index.vue'

export default function showOverlayLoading() {
  // 创建虚拟DOM。
  const vnode = createVNode(Index)
  // 渲染虚拟DOM
  console.log(`vnode-->`, vnode);

  const frag = document.createDocumentFragment()
  render(vnode, frag)
  document.body.appendChild(vnode.el, frag)

  return function hiddenOverlayLoading() {
    render(null, frag)
  }
}
  • src/router/index.js
import showOverlayLoading from '@/components/overlay'


// 全局前置守卫:登录态校验
const checkList = ['/person', '/store', '/update']//用于判断那些页面需要登录态校验。
let hiddenOverlayLoading = null//用于遮罩层
router.beforeEach(async (to, from, next) => {
  if (需要进行登录但没个人信息时) {
    hiddenOverlayLoading = showOverlayLoading()//开启遮罩层
    let info = await base.queryProfile()//异步用token拿到个人信息。
    if (!info) {
      // 真的没登录过。
      showFailToast('您还未登录,请先登录')
      next({
        path: '/login',
        query: {
          target: to.fullPath
        }
      })
      hiddenOverlayLoading?.()//移除遮罩层-用户真的没登录时。
      return
    }
  }

  next()
})
// 全局后置守卫
router.beforeEach((to, from) => {
  hiddenOverlayLoading?.()//移除遮罩层-其它情况,如用户已登录或者是无需个人信息页的情况。
})
export default router
import { createRouter, createWebHashHistory } from 'vue-router'
import routes from './routes'
import useBaseStore from '@/stores/base'
import { showFailToast } from 'vant'
import showOverlayLoading from '@/components/overlay'


const router = createRouter({
  history: createWebHashHistory(),
  routes
})

// 全局前置守卫:登录态校验
const checkList = ['/person', '/store', '/update']//用于判断那些页面需要登录态校验。
let hiddenOverlayLoading = null//用于遮罩层
router.beforeEach(async (to, from, next) => {
  const base = useBaseStore()//用于拿到个人信息。
  let profile = base.profile
  if (checkList.includes(to.path) && !profile) {
    hiddenOverlayLoading = showOverlayLoading()//开启遮罩层
    let info = await base.queryProfile()
    if (!info) {
      // 真的没登录过。
      showFailToast('您还未登录,请先登录')
      next({
        path: '/login',
        query: {
          target: to.fullPath
        }
      })
      hiddenOverlayLoading?.()//移除遮罩层
      return
    }
  }

  next()
})
// 全局后置守卫
router.beforeEach((to, from) => {
  hiddenOverlayLoading?.()//移除遮罩层

  let title = to.meta?.title
  document.title = !title ? '知乎日报' : `${title} - 知乎日报`
})
export default router

路由跳转时修改标签页标题

  • src/router/index.js

    import { createRouter, createWebHashHistory } from 'vue-router'
    import routes from './routes'
    
    
    const router = createRouter({
      history: createWebHashHistory(),
      routes
    })
    // 全局后置守卫
    router.beforeEach((to, from) => {
    
      let title = to.meta?.title
      document.title = !title ? '知乎日报' : `${title} - 知乎日报`
    })
    export default router
    
    import { createRouter, createWebHashHistory } from 'vue-router'
    import routes from './routes'
    import useBaseStore from '@/stores/base'
    import { showFailToast } from 'vant'
    import showOverlayLoading from '@/components/overlay'
    
    
    const router = createRouter({
      history: createWebHashHistory(),
      routes
    })
    
    // 全局前置守卫:登录态校验
    const checkList = ['/person', '/store', '/update']//用于判断那些页面需要登录态校验。
    let hiddenOverlayLoading = null//用于遮罩层
    router.beforeEach(async (to, from, next) => {
      const base = useBaseStore()//用于拿到个人信息。
      let profile = base.profile
      if (checkList.includes(to.path) && !profile?.value) {
        hiddenOverlayLoading = showOverlayLoading()//开启遮罩层
        let info = await base.queryProfile()
        if (!info) {
          // 真的没登录过。
          showFailToast('您还未登录,请先登录')
          next({
            path: '/login',
            query: {
              target: to.fullPath
            }
          })
          hiddenOverlayLoading?.()//移除遮罩层
          return
        }
      }
    
      next()
    })
    // 全局后置守卫
    router.beforeEach((to, from) => {
      hiddenOverlayLoading?.()//移除遮罩层
    
      let title = to.meta?.title
      document.title = !title ? '知乎日报' : `${title} - 知乎日报`
    })
    export default router
    
  • src/router/routes.js

    import Home from '@/views/Home.vue'
    const routes = [{
        path: '/',
        name: 'home',
        meta: { title: '首页' },
        component: Home
    }, {
        path: '/detail/:id',
        name: 'detail',
        meta: { title: '详情页' },
        component: () => import('@/views/Detail.vue')
    }, {
        path: '/login',
        name: 'login',
        meta: { title: '登录/注册页' },
        component: () => import('@/views/Login.vue')
    }, {
        path: '/person',
        name: 'person',
        meta: { title: '个人中心' },
        component: () => import('@/views/Person.vue')
    }, {
        path: '/store',
        name: 'store',
        meta: { title: '我的收藏' },
        component: () => import('@/views/Store.vue')
    }, {
        path: '/update',
        name: 'update',
        meta: { title: '更改信息' },
        component: () => import('@/views/Update.vue')
    }, {
        path: '/:pathMatch(.*)*',
        redirect: '/'
    }]
    export default routes
    

详情页收藏按钮

  1. 不用传统的登录态校验,但一些区域或功能需要用到个人信息。
  2. 所以需要优化个人信息的处理。
  3. 所有的涉及收藏的状态及操作和前后端数据交互,都放在全局公共状态里。
  4. 在需要用到收藏相关的状态及操作,都要调用全局公共状态方法。

优化个人信息的处理

  • src/router/index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import routes from './routes'
import useBaseStore from '@/stores/base'
import { showFailToast } from 'vant'
import showOverlayLoading from '@/components/overlay'


const router = createRouter({
  history: createWebHashHistory(),
  routes
})

// 全局前置守卫:登录态校验
const checkList = ['/person', '/store', '/update']//用于判断那些页面需要登录态校验。
let hiddenOverlayLoading = null//用于遮罩层
router.beforeEach(async (to, from, next) => {
  const base = useBaseStore()//用于拿到个人信息。
  let profile = base.profile//个人信息。
  // 除登录页之外,其余所有页面在没有存储登录者信息的情况下,都需要从服务器获取登录者信息进行存储。
  if (!profile && to.path !== '/login') {
    hiddenOverlayLoading = showOverlayLoading()//开启遮罩层
    let info = await base.queryProfile()
    // 如果是需要登录态校验的三个页面,再进行登录校验和跳转。
    if (checkList.includes(to.path) && !info) {
      // 真的没登录过。
      showFailToast('您还未登录,请先登录')
      next({
        path: '/login',
        query: {
          target: to.fullPath
        }
      })
      hiddenOverlayLoading?.()//移除遮罩层
      return
    }
  }
  next()
})
// 全局后置守卫
router.beforeEach((to, from) => {
  hiddenOverlayLoading?.()//移除遮罩层

  let title = to.meta?.title
  document.title = !title ? '知乎日报' : `${title} - 知乎日报`
})
export default router

收藏功能

基础pinia模板

  • src/stores/collect.js
import { defineStore } from 'pinia'
import { ref } from 'vue'
import API from '@/api'

const useCollectStore = defineStore('collect', () => {
  // 定义公共状态。

  // 派发的方法。

  // 暴露给外面用。
  return {

  }
})
export default useCollectStore
import { defineStore } from 'pinia'
import { ref } from 'vue'
import API from '@/api'

const useCollectStore = defineStore('collect', () => {
  // 定义公共状态。
  const collectList = ref(null)

  // 派发的方法。
  const queryCollectList = async () => {

  }
  const removeCollectList = async () => {

  }

  // 暴露给外面用。
  return {
    collectList,
    queryCollectList,
    removeCollectList,
  }
})
export default useCollectStore

收藏模块全局状态

  • 示例代码:

    • src/stores/collect.js 收藏相关的接口都用来源于这里的文件。

      import { defineStore } from 'pinia'
      import { ref } from 'vue'
      import API from '@/api'
      import { showFailToast, showSuccessToast } from 'vant'
      
      const useCollectStore = defineStore('collect', () => {
        // 定义公共状态。
        const collectList = ref(null)//用于保存收藏列表。
      
        // 派发的方法。
        // 查询收藏列表。
        const queryCollectList = async () => {
          let list = null
          try {
            let { code, data } = await API.storeList()
            if (+code === 0) {
              list = data
              collectList.value = list
            }
          } catch (error) {
            console.log(`error:-->`, error)
          }
          return list
      
        }
        // 删除收藏。
        // id为收藏id。
        const removeCollectList = async (id) => {
          if (!collectList?.value) {
            return
          }
          try {
            let { code } = await API.storeRemove(id)
            if (+code !== 0) {
              showFailToast('移除收藏失败')
              return
            }
            showSuccessToast(`移除收藏成功`)
            collectList.value = collectList.value.filter(item => {
              return +item.id !== +id
            })
          } catch (error) {
            console.log(`error:-->`, error)
          }
        }
        // 新增收藏。
        const insertCollectList = async (newsId) => {
          try {
            let { code } = await API.storeAdd(newsId)
            if (+code !== 0) {
              showFailToast('收藏失败')
              return
            }
            await queryCollectList()
            showSuccessToast(`收藏成功`)
          } catch (error) {
            console.log(`error:-->`, error)
          }
        }
      
        // 暴露给外面用。
        return {
          collectList,
          queryCollectList,
          removeCollectList,
          insertCollectList,
        }
      })
      export default useCollectStore
      
    • src/views/Detail.vue 详情页

      1. 由于没有登录而进入到登录页,不能直接用push(),因为会添加一条记录,导致登录成功后重新跳转回详情页之后,会新增一条详情记录。此时登录成功后点击返回,依旧是在详情页。所以这里只能使用replace()进登录页,用target字段标识,则在登录成功后,退回到详情页。
        • 这个在登录页中做特殊处理,如果有target字段标识,则在登录成功后,跳转到target字段对应的路径中。
      2. 而用replace(),也会丢失历史记录。在登录页中点击我们写的后退组件,不是返回详情页,而是回到详情页的上一条历史记录。即在详情页用replace()进登录页之后,从登录页点击后退,会跳转回首页
        • 这个需要在我们写的后退组件中做特殊处理。
      
      
      
      
      
      
    • src/components/NavBack.vue

      
      
      
      
      
      
    • src/views/Login.vue

      
      
      
      
      
      
  • 关于没登录跳转到登录页的核心处理代码:

    • src/views/Detail.vue 详情页

      1. 由于没有登录而进入到登录页,不能直接用push(),因为会添加一条记录,导致登录成功后重新跳转回详情页之后,会新增一条详情记录。此时登录成功后点击返回,依旧是在详情页。所以这里只能使用replace()进登录页,用target字段标识,则在登录成功后,退回到详情页。
        • 这个在登录页中做特殊处理,如果有target字段标识,则在登录成功后,跳转到target字段对应的路径中。
      2. 而用replace(),也会丢失历史记录。在登录页中点击我们写的后退组件,不是返回详情页,而是回到详情页的上一条历史记录。即在详情页用replace()进登录页之后,从登录页点击后退,会跳转回首页
        • 这个需要在我们写的后退组件中做特殊处理。
      
      
      
      
    • src/components/NavBack.vue

      
      
      
      
    • src/views/Login.vue

      
      
      
      

打包

  1. vite按需导入插件vite-plugin-impvant@4的按需导入插件有冲突,会导致vant4中的函数调用式组件会导入与实际vant组件用到的样式文件地址不同的路径。
  • 示例

    • vite.config.js

      import { fileURLToPath, URL } from 'node:url'
      import { defineConfig } from 'vite'
      import vue from '@vitejs/plugin-vue'
      import vueJsx from '@vitejs/plugin-vue-jsx'
      import viteImp from 'vite-plugin-imp'
      import Components from 'unplugin-vue-components/vite'
      import { VantResolver } from 'unplugin-vue-components/resolvers'
      import pxtorem from 'postcss-pxtorem'
      
      /* https://vitejs.dev/config/ */
      export default defineConfig({
        base: './',
        plugins: [
          vue(),
          vueJsx(),
          /* // 按需导入插件 https://github.com/onebay/vite-plugin-imp
          // 与vant4的按需导入有冲突。
          viteImp({
            libList: [
              {
                libName: 'lodash',
                libDirectory: '',
                camel2DashComponentName: false
              }
            ]
          }), */
          // vant@4的按需导入
          Components({
            resolvers: [
              VantResolver()
            ]
          })
        ],
        resolve: {
          alias: {
            '@': fileURLToPath(new URL('./src', import.meta.url))
          }
        },
        /* 服务配置 */
        server: {
          host: '127.0.0.1',
          proxy: {
            '/api': {
              target: 'http://127.0.0.1:7100',
              changeOrigin: true,
              rewrite: path => path.replace(/^\/api/, '')
            }
          }
        },
        /* 生产环境 */
        build: {
          assetsInlineLimit: 1024 * 10,
          minify: 'terser',
          terserOptions: {
            compress: {
              drop_console: true,
              drop_debugger: true
            }
          },
          rollupOptions: {
            external: ['']
          }
        },
        /* CSS样式 */
        css: {
          postcss: {
            plugins: [
              pxtorem({
                rootValue: 37.5,
                propList: ['*']
              })
            ]
          },
          preprocessorOptions: {
            less: {
              additionalData: `@import "@/assets/var.less";`
            }
          }
        }
      })
      
  • 核心:

    • vite.config.js

      import viteImp from 'vite-plugin-imp'
      export default defineConfig({
        plugins: [
          // 按需导入插件 https://github.com/onebay/vite-plugin-imp
          // 与vant4的按需导入有冲突。
          viteImp({
            libList: [
              {
                libName: 'lodash',
                libDirectory: '',
                camel2DashComponentName: false
              }
            ]
          }),
        ],
      })
      

      不兼容

      import Components from 'unplugin-vue-components/vite'
      import { VantResolver } from 'unplugin-vue-components/resolvers'
      export default defineConfig({
        plugins: [
          Components({
            resolvers: [
              VantResolver()
            ]
          })
        ],
      })
      

TS

  • 主要就是为了开发时限定类型,让代码更严谨。
    1. 开发时用ts代替js,用tsx代替jsx
  1. 类型 对各种变量/值,进行类型限制
  2. 类型断言
  3. 在函数中使用各种声明和限制
  4. 在类中的处理 public/private/protected

与es5及es6的关系

类型的限定

  1. 对各种变量/值,进行类型限制

常见类型

/*
 let/const 变量:类型限定 = 值
   + 变量不能是已经被 lib.dom.d.ts 声明的,例如:name
     但可以把当前文件变为一个模块 “ 加入 export 导出 ”,这样在这里声明的变量都是私有的了
   + 类型限定可以是小写和大写
     + 一般用小写
     + 大写类型可以描述实例
     + 大写的 Object 不用,因为所有值都是其实例;想要笼统表示对象类型,需要用 object !
   + 数组的限定
     let arr:number/string[]
     let arr:(number|string)[]
     let arr:Array 泛型
     ...
   + TS中的元祖:类型和长度固定
     let tuple:[string, number] = ['abc', 10]
     可基于数组的方法操作元祖
   + TS中的枚举
     enum USER_ROLE {
        ADMIN,
        USER
     }
   + null 和 undefined 只能赋予本身的值
   + void 用于函数的返回
     function fn():void{ ... }
     function fn():void | null{ ... }
   + never 不可能出现的值「任何类型的子类型」
     function fn():never{ 
        // 报错 OR 死循环 等
     }
   + any 任意类型
 */

类型断言

  1. 一定小心使用,相关于程序员用人格保证了,就是不是,ts编译器也会把该值当成是断言的类型。
/*
 类型断言:
 @1 声明变量,没有给类型限定,没有赋值的时候,默认类型是any
 @2 如果最开始声明的时候赋值了,则会按照此时值的类型自动推导
 @3 联合类型
   let name:string | number
   + 在没有赋值之前,只能使用联合类型规定的类型,进行相关的操作
   + 不能在变量赋值之前调用其方法
   + !. 断言变量一定有值
   + as 认定是啥类型的值
   (name! as number).toFixed()
 @4 字面量类型
   let direction:'top'|'right'|'down'|'left' 赋的值只能是这四个中的一个{限定了值}
   可以基于 type (类型别名)优化
     let Direction = 'top'|'right'|'down'|'left'
     let direction:Direction = ...
 */

函数类型

  1. 在函数中使用各种声明和限制。
/*
 函数的玩法
   普通函数:声明参数和返回值类型
     function fn(x:number,y:number):number{...}
   函数表达式:在普通函数基础上,对赋值的函数做类型校验 
     type Fn = (x:number,y?:number) => number
     let fn:Fn = function(x,y){...}
 */

类的类型

高级类型与联合类型

接口

接口与type

泛型

ts的应用

  1. @vue/cli中使用
  2. vite中使用

在项目根目录中配置

  • Vue3进阶/knowledge/env.d.ts 这个很重要,要不在.vue后缀类型文件中会有报错。

    /// 
    
    // 声明导入 .vue 文件的类型「防止波浪线报错」
    declare module '*.vue' {
      import type { DefineComponent } from 'vue'
      const component: DefineComponent<{}, {}, any>
      export default component
    }
    
  • Vue3进阶/knowledge/tsconfig.app.json

    {
      "extends": "@vue/tsconfig/tsconfig.dom.json",
      "include": [
        "env.d.ts",
        "src/**/*",
        "src/**/*.vue"
      ],
      "exclude": [
        "src/**/__tests__/*"
      ],
      "compilerOptions": {
        "composite": true,
        "baseUrl": ".",
        "paths": {
          "@/*": [
            "./src/*"
          ]
        }
      }
    }
    
  • Vue3进阶/knowledge/tsconfig.json 看对应的pdf文档

    {
      "files": [],
      "references": [
        {
          "path": "./tsconfig.node.json"
        },
        {
          "path": "./tsconfig.app.json"
        }
      ]
    }
    
  • Vue3进阶/knowledge/tsconfig.node.json

    {
      "extends": "@tsconfig/node18/tsconfig.json",
      "include": [
        "vite.config.*",
        "vitest.config.*",
        "cypress.config.*",
        "nightwatch.conf.*",
        "playwright.config.*"
      ],
      "compilerOptions": {
        "composite": true,
        "module": "ESNext",
        "types": [
          "node"
        ]
      }
    }
    

简历

注意细节

  1. 先有面试再说后面的事。
  2. 先有word版写好,后面再复制到网站的模板上。
  3. 先全员海投,有面试机会再看具体信息。(无脑投)
  4. BOSS直聘一天100个左右,其它投到上限。(用一个小时左右投)
  5. 先看到有的,后面去试,可以准备给朋友。(可以记录下要面试的题)。
  6. 面试时,一般就说在我之前的项目中…而不要八股文。(个人真实就好了)
  7. 带上笔和本-面试遇到不会的问题,是面试的开始,而不是结束。
    • 当上不会的题或东西,当着面试官的面来记,再说后面再查,晚上回去再查。这个也要真查,因为提到的可能就是新的主流东西。
      • 再问对方写代码了多少年,夸奖面试官。多少年之后,比自己少的,夸对方厉害。比自己多,不愧是xx年工作经验的。

招聘平台

  • 招聘平台
    • BOSS直聘(主要)
      • 基于聊天去投递简历,要准备好简历和聊天用语。
    • 51job(前程无忧)
    • 拉钩
    • 猎聘网

投递时间

  • 投的时间:周一到周六,每天9:30开始、下午14:00开始(不要睡懒觉)。

    • 剩下的时间要复习。
    • 整理好css、js,之后是vue和react,并写页面。
      • 进阶学一些算法。
    • 面试之后要录音,电脑面试也要录音,而现场面试时进公司就录音。
    • 面试之后要再整理面试题,如果记不清,则要听录音。同时再总结出最佳的面试题回答。
    • 早睡早起:早上不要晚于8:30、晚上不要晚于12:00、在此期间不要玩游戏。
  • 老家或北京之类的都投。

个人预期

  • 学习完ts和uniapp。

职业规划和离职原因

  • 职业规划

    • 随意一些,按个人真实的来。
    • 走技术,学习全栈。
      • 学会后端知识点如:node。
      • 学习uniapp。
      • 学习taro。
      • 看vue3源码和react源码和UI框架源码,如:
        • element-ui源码。
        • antd源码。
        • vant源码。
      • 学习前端算法。
    • 走管理,熟悉公司的业务,会培训带领新人,写文档。会和后端进行交互,
  • 离职原因

    • 不要说上家公司坏话,如技术栈不新、公司抠门、领导差之类的。
    • 尽量多写客观原因:
      • 可以说公司业绩不太好-公司暗示要解散项目组。
        • 公司倒闭了,但压了自己的工资,老大那边压力也大,后面帮做最后一个项目里,结束最后一个业务后,就结束了。
      • 要结婚之类的。

进阶参考

  1. ts中文网

你可能感兴趣的:(重返学习,vue,学习,vue.js,javascript)