Hand in hand teaching you to encapsulate calendar components with Vue

Time:2021-6-14

Hello, you brave little friends, Hello, I’m your mouth strong king small five, healthy, brain is not sick
 

I have a wealth of hair loss skills, you can become a veteran

It’s my main idea that I can write and discard as soon as I see it. It’s my characteristic to pick my feet when I’m cooking. There’s a trace of strength in my humble life. It’s the greatest comfort for me that stupid people have silly blessings

Welcome toXiao WuOfEssay seriesofHand in hand teaching you to encapsulate calendar components with Vue.

Write on the front

Code link: Portal – ajun568

The final effect is shown on both feet

Hand in hand teaching you to encapsulate calendar components with Vue

requirement analysis

Demand analysis is nothing more than a process of what you want and gradual refinement. After all, no one can eat a big cake in one bite, so let’s cut the cake first and eat it bit by bit. The following is a basic calendar component based on a specific scenario. I hope you can spray it lightly. Welcome to leave a message for us

Hand in hand teaching you to encapsulate calendar components with Vue

Scene: inMobile terminalPassed inSwitch dateTo switch the revenue data, the display form is the calendar above and the corresponding data belowDaily data.

Based on this scenario, we analyze the requirements of the calendar function

  • In general scenarios, we prefer the data of the day. Therefore, the first entry should show the current month and the selected date is today
  • Click on the date, it should be able to switch accurately, otherwise what is the use of it, when the bottle
  • The scene is based on the mobile terminal, and the interactive mode is selected to experience better sliding switching, left sliding to previous month and right sliding to next month
  • After sliding to switch months, select the first day of the month
  • The display area of the mobile terminal is very valuable, so it is very important to reduce the occupied space. At this time, the weekly view has a place to use. Interactively, you can slide up to switch to the weekly view and pull down to switch back to the monthly view
  • Clear month view slide cut month, week view slide cut week
  • After sliding to switch weeks, select the first day of the week. If there is No. 1 after sliding left, select No. 1

Hand in hand teaching you to encapsulate calendar components with Vue

Structure and style

First split the calendar, you can split it up and down into two partsweekSection, and belowdataThe number of columns is limited to 7 days a week7 columns, the number of rows will change withDays of the monthandWhere’s number oneBut it’s different

The mobile terminal should also adapt the layout according to the screen width,flexLayout is a good choice. Let’s simulate the data part. First, create an array with length of 40 and data of 0 as follows:

const dataArr = Array(40).fill(0, 0, 40)

Now, we want to display 7 in each row, and move them down in turn. Let’s think about it. If it was you, what would you do?

  • Parent element settings

    • flex-direction: used to define the spindle direction
    • flex-wrap: used to define whether to wrap lines
    • flex-flow: define at the same timeflex-directionandflex-wrap
  • Child element settings

    • flex-basis: used to set the scaling reference value. You can set the specific width or percentage. The default value is auto
    • flex-grow: used to set the magnification. The default value is 0. If there is space left, the element will not be enlarged
    • flex-shrink: used to set the zoom out ratio. The default value is 1. If the space is insufficient, the zoom out ratio will be equal. If set to 0, it will not shrink
    • flex : flex-growflex-shrinkandflex-basisAbbreviation for

To sum up, we can set the style to  father   flex: row wrap   son   flex: 0 0 14.285% (1/7 ≈ 14.285%)

design sketch

Hand in hand teaching you to encapsulate calendar components with Vue

code snippet

Hand in hand teaching you to encapsulate calendar components with Vue

At this time, a layer structure can be added to fix the width and height of the sub elements to 40 ✖️ 40, convenient to handle the selected style

Let’s sketch two styles at will, as shown below

Hand in hand teaching you to encapsulate calendar components with Vue

Displays the current month and the date of the selected day

Imagine out of thin air where there is a direct picture to the intuitive, just like the boss’s pie where there is money to the real, next we combined with the following picture for further analysis, the picture is my interception of the mobile phone calendar

Hand in hand teaching you to encapsulate calendar components with Vue

First of all, since today is selected by default, let’s get the current date first

//Get current date
getCurrentDate() {
  this.selectData = {
    year: new Date().getFullYear(),
    month: new Date().getMonth() + 1,
    day: new Date().getDate(),
  }
}

Let’s take a look at this picture, regardless of the part in the blue box. To show the date of the current month, we only need to know the following two points, and then do the for loop

  1. The number of days in the current month
  2. Where should the first day of the current month be displayed

So easy! Don’t be too simple

Hand in hand teaching you to encapsulate calendar components with Vue

Days of the month

“One three five seven eight, thirty-one days is never bad”The number of days in every month is fixed except February, which is a normal leap year. If you look at it, isn’t it the end of February

const { year } = this.selectData
let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

if ((year % 4 === 0 && year % 100 !==  0) || year% 400 = = = 0) {// leap year processing
  daysInMonth[1] = 29
}

Location of the first day of the month

If you want to know the location of the first day of the month, you can change your mind. In fact, you just want to know the day of the week on the first day of the month. AI, isn’t it a coincidence to take the date of the first day of the monthgetDay()Isn’t that the end of it

const { year, month } = this.selectData
const monthStartWeekDay = new Date(year, month - 1, 1).getDay()

Next, we fill in the data and leave blank before and after. The code and effect are as follows:

?‍♂️ Code

Hand in hand teaching you to encapsulate calendar components with Vue

?‍♂️ Image

Hand in hand teaching you to encapsulate calendar components with Vue

Date switch and month switch

Date switch = change the number of child elements in the current arrayisSelected

//Switch click date
checkoutDate(selectData) {
  if (selectData.type !== ' Normal ') return // non valid date cannot be selected

  This. Selectdata. Day = selectdata. Day // assign a value to the selected date

   //Finds the index of the currently selected date
  const oldSelectIndex = this.dataArr.findIndex(item => item.isSelected && item.type === 'normal')
  //Find the index of the new switching date (Tips: Here you can also directly pass the index value to the user
  const newSelectIndex = this.dataArr.findIndex(item => item.day === selectData.day && item.type === 'normal')

  //Change the isselected value
  if (this.dataArr[oldSelectIndex]) this.$set(this.dataArr[oldSelectIndex], 'isSelected', false)
  if (this.dataArr[newSelectIndex]) this.$set(this.dataArr[newSelectIndex], 'isSelected', true)
}

Month switch = regenerate the month corresponding to the new monthdataArr, and select the first day of the month

tips:The point to note here is,The month before JanuaryandThe next month of DecemberFor example:

checkoutPreMonth() {
  let { year, month, day } = this.selectData
  if (month === 1) {
    year -= 1
    month = 12
  } else {
    month -= 1
  }

  this.selectData = { year, month, day: 1 }
  this.dataArr = this.getMonthData(this.selectData)
},

today

checkoutCurrentDate() {
  this.getCurrentDate()
  this.dataArr = this.getMonthData(this.selectData)
},

At this point, a basic month view is completed

Hand in hand teaching you to encapsulate calendar components with Vue

Sliding lunar cutting

Next, let’s optimize the month view and add the function of sliding to cut the month. Let’s take a look at the implementation effect

Hand in hand teaching you to encapsulate calendar components with Vue

Take the left slide as an example

  • In the process of sliding, we can see some data of next month
  • If the sliding distance is too small, it will automatically rebound to the current view
  • If the slide exceeds a certain distance, it will automatically slide to the next month

touch

Crime requires tools. If you want to trigger a sliding event, you have to find the corresponding tool first

Hand in hand teaching you to encapsulate calendar components with Vue

  • touchstart: triggered when the finger touches the screen
  • touchmove: triggered when a finger drags in the screen
  • touchend: triggered when the finger leaves the screen

Depending on this event alone, you can’t see part of the data of the next month in the sliding process. If you want to see the data in the sliding process, this is a typical carousel scenario. In essence, it’s a videotransformIt’s a process of change

Hand in hand teaching you to encapsulate calendar components with Vue

At this point, we adjust the next page structure, by thedataArrThe essence of the single-layer cycle is shown in the figure above[pre, current, next]array

This step involves a lot of code changes. Next, we mainly use the newly introduced variables to straighten out the ideas. When the ideas are clear, let’s go, come on baby!

Alldataarr: [], // carousel array
Isselectedcurrentdate: false, // click the date of the current month
Translateindex: 0, // the location of the carousel
Transitionduration: 0.3, // animation duration
Needanimation: true, // do you need animation to slide left and right
Istouching: false, // is it sliding
Touchstartpositionx: null, // the value of initial slide x
Touchstartposition: null, // value of initial sliding y
Touch: {// the percentage of the horizontal and vertical sliding distance of this touch event
  x: 0,
  y: 0,
},

allDataArr-Carousel array

❓ When to assign a value to this array

I don’t know[pre, current, next]When any value changes in, andpreandnextAll the changes are dependent oncurrentWow, interesting! watch watch watch !!!

isSelectedCurrentDate-Do you want to click the date of the current month

❓ When you click to switch data, becauseisSelectedChanges in,watchListen and perform the assignment operation, but there is no need to regenerate at this timepreandnext

translateIndex-Location of carousel

For controlpre, current, nextPosition, when the sliding cut is triggered, by changingtranslateIndexTo change the position. Revert to the initial value when reassigning

touchStartPositionX, touchStartPositionY, touch

These three are to determine the sliding direction and distance, and in what direction?(don’t tell me that you are willful and just want to slide sideways)How far does it slide? After release, rebound treatment is done for small sliding distance, and switch treatment is done for large sliding distance(combination)translateIndexI know you know

needAnimation-Do you need animation to slide left and right

Hand in hand teaching you to encapsulate calendar components with Vue

When we look at the picture and talk (), do we feel that the animation is strange, but we don’t know where it is, because when the animation is in progress, we are rightallDataArrAfter performing the assignment operation, we delay the assignment operation in the timer, and the effect is as follows ():

Hand in hand teaching you to encapsulate calendar components with Vue

Is there an obvious process of repeated horizontal jump, because when we slide past, we are in the middlenextBut the last thing to come back to iscurrentHow can this little question limit our smart brain? It’s going back tocurrentRemove the animation, not perfect to solve the problem

Hand in hand teaching you to encapsulate calendar components with Vue

Assign part of the code fragment:

Hand in hand teaching you to encapsulate calendar components with Vue

Hand in hand teaching you to encapsulate calendar components with Vue

Hand in hand teaching you to encapsulate calendar components with Vue

Switch week view

Let’s analyze the next week’s process

Hand in hand teaching you to encapsulate calendar components with Vue

Bingo is onetransformY+heightThe process of

aboutheightIt is a process of repeated horizontal jump from total height to single row height. The height of each row is fixed. Total height = single row height * total number of rows

Isweekview: false, // week view or month view
Itemheight: 50, // calendar line height
Linenum: 0, // total number of rows in current view

this.lineNum = Math.ceil(this.dataArr.length / 7)

abouttransformY, its moving distance = (current row number – 1) * single row height

Offset Y: 0, // Y-axis offset of week view

//Dealing with data changes in weekly view
dealWeekViewData() {
  const selectedIndex = this.dataArr.findIndex(item => item.isSelected)
  const indexOfLine = Math.ceil((selectedIndex + 1) / 7)
  this.offsetY = -((indexOfLine - 1) * this.itemHeight)
},

Complete view information

Before sliding the week view, let’s complete the view informationdaraArrFill in the blank of the corresponding date

Hand in hand teaching you to encapsulate calendar components with Vue

Not to mention the filling of year and month, but the filling of next day

nextIt’s simple,Number of cycles = 7 – last row days = 7 – week index of the 1st day of the next month(tip: it should be noted that if the index of the first day of the next month is 0, it means that there is no blank space to fill, and naturally there is no need to cycle),dayAssignment ofIncrease from No.1That’s fine

const nextInfo = this.getNextMonth()

let nextObj = {
  type: 'next',
  day: i + 1,
  month: nextInfo.month,
  year: nextInfo.year,
}

Let’s talk about it againpre, Number of cycles = 7 – number of days in the first row = week index of the first day of the month, dayThe assignment of is equal toReverse order of date of last month = > days of last month – (index of week 1 of current month – (index + 1))

const preInfo = this.getPreMonth(date)

let preObj = {
  type: 'pre',
  day: daysInMonth[preInfo.month - 1] - (monthStartWeekDay - i - 1),
  month: preInfo.month,
  year: preInfo.year,
}

❓ heregetPreMonth()Function transferdateWhy

To put it bluntly, date is a reference. It will be passed on to whoever gets it last month; andgetNextMonth()Why don’t you pass it? It doesn’t matter. Pass it or not. It increases from 1. Who will waste feelings on an unimportant matter

When you click a date other than the current month, you can switch the month accordingly. At this time, the date after switching is the selected date instead of the 1st

Sliding week

In the process of view switching, the friction with us is still with uspreArrandnextArrSince we can’t get rid of them, why don’t we squeeze their value to the extreme, which is in line with the maximization of interests. We change the same data before and after the rampant data into the previous week and the next week respectively. After all, destruction is the better creation

Hand in hand teaching you to encapsulate calendar components with Vue

If you want to change the civet cat for the prince, you have to find the civet cat first, and then find the prince before you can switch the two. Let’s take the previous week as an example to find the civet cat and the prince

  • Civet cat-lastWeek

No.1 if it is not the first line of data, last week = previous line. Through the current number of lines, get the index of data at both ends, subtract 7 to get the index of data at both ends of the previous week, and then get the data of the previous week

No.2 if it is the first line at present, it can be further divided into: whether the first data item is No.1; if it is, the last line of the previous month will be taken; If not, the data in the penultimate row of the previous month will be taken(Tips: at this time, the last line of last month is equal to the current first line); The above two points can also be considered as finding the line of a specific date in the previous month

  • Prince – the current line of parallel world
//Get the location information needed to process the week view
getInfoOfWeekView(selectedIndex, length) {
  Const indexofline = math.ceil ((selectedindex + 1) / 7) // number of current lines
  Const totalline = math.ceil (length / 7) // total number of rows
  Const slicestart = (indexofline - 1) * 7 // left index of current line
  Const sliceend = slicestart + 7 // right index of current line

  return { indexOfLine, totalLine, sliceStart, sliceEnd }
},

//Process lastweek, nextwaek, and return the index of the substitution line
dealWeekViewSliceStart() {
  const selectedIndex = this.dataArr.findIndex(item => item.isSelected)
  const {
    indexOfLine,
    totalLine,
    sliceStart,
    sliceEnd
  } = this.getInfoOfWeekView(selectedIndex, this.dataArr.length)

  this.offsetY = -((indexOfLine - 1) * this.itemHeight)

  //Previous week's data
  if (indexOfLine === 1) {
    const preDataArr = this.getMonthData(this.getPreMonth(), true)
    const preDay = this.dataArr[0].day - 1 || preDataArr[preDataArr.length - 1].day
    const preIndex = preDataArr.findIndex(item => item.day === preDay && item.type === 'normal')
    const { sliceStart: preSliceStart, sliceEnd: preSliceEnd } = this.getInfoOfWeekView(preIndex, preDataArr.length)
    this.lastWeek = preDataArr.slice(preSliceStart, preSliceEnd)
  } else {
    this.lastWeek = this.dataArr.slice(sliceStart - 7, sliceEnd - 7)
  }

  //Next week data
  if (indexOfLine >= totalLine) {
    const nextDataArr = this.getMonthData(this.getNextMonth(), true)
    const nextDay = this.dataArr[this.dataArr.length - 1].type === 'normal' ? 1 : this.dataArr[this.dataArr.length - 1].day + 1
    const nextIndex = nextDataArr.findIndex(item => item.day === nextDay)
    const { sliceStart: nextSliceStart, sliceEnd: nextSliceEnd } = this.getInfoOfWeekView(nextIndex, nextDataArr.length)
    this.nextWeek = nextDataArr.slice(nextSliceStart, nextSliceEnd)
  } else {
    this.nextWeek = this.dataArr.slice(sliceStart + 7, sliceEnd + 7)
  }

  return sliceStart
},

dealWeekViewData() {
  const sliceStart = this.dealWeekViewSliceStart()
  this.allDataArr[0].splice(sliceStart, 7, ...this.lastWeek)
  this.allDataArr[2].splice(sliceStart, 7, ...this.nextWeek)
},

Optimize code

Here we are basically done. Let’s sum up the remaining problems and deal with them

  • Some bad animations: in this scene, all the strange animations are created bytransitionDurationSo we need to figure out when we need animation, when we don’t need it, and when we don’t need it, just assign it to 0
  • Similar to the Caton effect: in this scene, almost all the catons and delays are evilsetTimeoutSo we should think about when we need it and when to abandon it decisively
  • Finally, add a touch bar at the bottom to make it more beautiful

Complete code

Long picture alert, please click here to open a larger picture to watch, or you can go directly to mygithubView on,Portal – ajun568

Hand in hand teaching you to encapsulate calendar components with Vue

Hand in hand teaching you to encapsulate calendar components with Vue

Reference link

GitHub – lightweight, high performance calendar component based on Vue 2.0

Recommended Today

Five simple steps to master tensorflow tensor

Author | Orhan g. YAL ç ı nCompile VKSource: towards Data Science If you are reading this article, I believe we have similar interests and will engage in similar industries now / in the future. In this article, we will delve into the details of tensorflow tensor. We will cover all topics related to tensorflow’s […]