اذهب إلى المحتوى

السؤال

نشر

السلام عليكم و عيد مبارك.

أريد القيام بanimation عند الscroll في صفحة الويب كما يلي:

Capture.JPG.8ba4e9db4016b0db8f9f371019e6167e.JPG

المشكل الحاصل هو في القيمة percentage لكل عنصر حيث تمت إعادة نفس القيمة لكل العناصر (35%).

الكود الذي قمت به:

function App() {
  const skills = [
    {
      id: 1,
      language: 'html',
      progress: 70,
    },
    {
      id: 2,
      language: 'css',
      progress: 65,
    },
    {
      id: 3,
      language: 'javascript',
      progress: 50,
    },
    {
      id: 4,
      language: 'github',
      progress: 40,
    },
    {
      id: 5,
      language: 'jest',
      progress: 35,
    },
  ]

  const progressAnim = useRef()

  const [percentage, setPercentage] = useState(1)

  window.onscroll = function () {
    if (window.scrollY >= progressAnim.current.offsetTop - 300) {
      skills.map(skill => setPercentage(skill.progress))
    }
  }
  return (
    <div className="App">
      <Section src = {img_1}/>
      <Section src = {img_2}/>
      <div className="skills" ref={progressAnim}>
        {
          skills.map(skill => (
            <Progress 
              key = {skill.id}
              percentage = {percentage}
              circleWidth = "200"
              name = {skill.language}
            />
          ))
        }
      </div>
    </div>
  );
}

 

Recommended Posts

  • 0
نشر

عدل الكود الخاص بك للشكل التالي :

function App() {
	const skills = [
		{
			id: 1,
			language: 'html',
			progress: 70,
		},
		{
			id: 2,
			language: 'css',
			progress: 65,
		},
		{
			id: 3,
			language: 'javascript',
			progress: 50,
		},
		{
			id: 4,
			language: 'github',
			progress: 40,
		},
		{
			id: 5,
			language: 'jest',
			progress: 35,
		},
	];

	const progressAnim = useRef();
	const [animate, setAnimate] = useState(false);

	window.onscroll = function () {
		if (window.scrollY >= progressAnim.current.offsetTop - 300) {
			setAnimate(true);
		}
	};

	return (
		<div className="App">
			<Section src={img_1} />
			<Section src={img_2} />
			<div className="skills" ref={progressAnim}>
				{
					skills.map(skill => (
						<ProgressItem data={skill} animate={animate} />
					))
				}
			</div>
		</div>
	);
}

const ProgressItem = ({ data, animate }) => {
	const [percentage, setPercentage] = useState(1);
	useEffect(() => {
		if (animate) setPercentage(data.percentage)
	}, [animate]);
	return (
		<Progress
			key={data.id}
			percentage={percentage}
			circleWidth="200"
			name={data.language}
		/>
	)
};

بحيث تجعل لكل عنصر الحالة percentage الخاصة به.

  • 0
نشر

السبب في أن جميع العناصر لديها نفس القيمة percentage هو لأنه تم تحديث القيمة في الحلقة forEach بشكل متكرر وتم استخدام نفس الحالة لجميع العناصر.

ولذلك، عليك باستخدام دالة محدثة لتحديث قيمة percentage لكل عنصر في الحدث onscroll.

ويمكن تغيير الكود كالتالي:

const [percentage, setPercentage] = useState({})

window.onscroll = function () {
  if (window.scrollY >= progressAnim.current.offsetTop - 300) {
    skills.forEach(skill => {
      setPercentage(prevPercentage => ({
        ...prevPercentage,
        [skill.id]: skill.progress
      }))
    })
  }
}

return (
  <div className="App">
    <Section src={img_1} />
    <Section src={img_2} />
    <div className="skills" ref={progressAnim}>
      {skills.map(skill => (
        <Progress
          key={skill.id}
          percentage={percentage[skill.id] || 0}
          circleWidth="200"
          name={skill.language}
        />
      ))}
    </div>
  </div>
)

حيث تم تحويل القيمة percentage إلى كائن حيث يتم استخدام معرف العنصر كمفتاح.

ثم استخدام دالة محدثة لتحديث قيمة percentage بشكل منفصل لكل عنصر. أخيراً، واستخدام القيمة المحدثة في كل عنصر في عنصر تقدم الدائرة Progress.

طريقة أخرى 

و هناك طريقة أخرى لحل هذه المشكلة، وهي باستخدام useEffect بدلاً من استخدام دالة محدثة في حدث onscroll، كالتالي:

const [percentage, setPercentage] = useState({})

useEffect(() => {
  const handleScroll = () => {
    if (window.scrollY >= progressAnim.current.offsetTop - 300) {
      const newPercentage = {}
      skills.forEach(skill => {
        newPercentage[skill.id] = skill.progress
      })
      setPercentage(newPercentage)
    }
  }
  window.addEventListener('scroll', handleScroll)
  return () => {
    window.removeEventListener('scroll', handleScroll)
  }
}, [skills, progressAnim])

return (
  <div className="App">
    <Section src={img_1} />
    <Section src={img_2} />
    <div className="skills" ref={progressAnim}>
      {skills.map(skill => (
        <Progress
          key={skill.id}
          percentage={percentage[skill.id] || 0}
          circleWidth="200"
          name={skill.language}
        />
      ))}
    </div>
  </div>
)

باستخدام useEffect بدلاً من الحدث onscroll، يتم استدعاء دالة handleScroll في كل مرة يتم فيها التمرير، وتحدث قيمة percentage فقط إذا تم تمرير العنصر المطلوب.

ثم إضافة الحدث الذي يتم استدعاءه إلى النافذة في useEffect. وفي النهاية، وإزالة الحدث عند إزالة المكون.

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...