কেন প্রতিশ্রুতি ব্যবহার করে সিএসএস সম্পত্তি সেট করা হয়? তত্ক্ষণাত ব্লকটিতে আসলে তা ঘটে না?


11

দয়া করে নীচের স্নিপেটটি চেষ্টা করে চালান, তারপরে বক্সে ক্লিক করুন।

const box = document.querySelector('.box')
box.addEventListener('click', e => {
  if (!box.style.transform) {
    box.style.transform = 'translateX(100px)'
    new Promise(resolve => {
      setTimeout(() => {
        box.style.transition = 'none'
        box.style.transform = ''
        resolve('Transition complete')
      }, 2000)
    }).then(() => {
      box.style.transition = ''
    })
  }
})
.box {
  width: 100px;
  height: 100px;
  border-radius: 5px;
  background-color: #121212;
  transition: all 2s ease;
}
<div class = "box"></div>

আমি যা ঘটতে প্রত্যাশা করি:

  • ক্লিক হয়
  • বাক্সটি 100px দ্বারা অনুভূমিকভাবে অনুবাদ শুরু করে (এই ক্রিয়াটি দুই সেকেন্ড সময় নেয়)
  • ক্লিক করার পরে, একটি নতুন তৈরিও Promiseহয়। ভিতরে বলেছেন Promise, একটি setTimeoutফাংশন 2 সেকেন্ডে সেট করা আছে
  • ক্রিয়াটি সম্পন্ন হওয়ার পরে (দুই সেকেন্ড সময় কেটে গেছে), setTimeoutএর কলব্যাক ফাংশনটি চালায় এবং কোনওটিতে সেট transitionকরা নেই। এটি করার পরে, এটির আসল setTimeoutমানটিতেও ফিরে আসে transform, এইভাবে বাক্সটি আসল অবস্থানে উপস্থিত হয়।
  • বাক্সটি এখানে কোনও স্থানান্তর প্রভাবের সমস্যা ছাড়াই মূল স্থানে উপস্থিত হবে
  • এই সমস্ত সমাপ্তির পরে, transitionবাক্সটির মানটিকে তার মূল মূল্যে সেট করুন

তবে, যেমন দেখা যায়, চলমান অবস্থায় transitionমানটি মনে হয় না none। আমি জানি যে উপরোক্ত অর্জনের জন্য অন্যান্য পদ্ধতি রয়েছে, উদাহরণস্বরূপ কীফ্রেম ব্যবহার করা এবং transitionendতবে কেন এটি ঘটে? আমি স্পষ্টভাবে সেট transitionতার মূল মান ফিরে শুধুমাত্র পরsetTimeout তার কলব্যাক শেষ, এইভাবে প্রতিশ্রুতি সমাধানে।

সম্পাদনা

অনুরোধ অনুসারে, কোডযুক্ত একটি জিআইএফ সমস্যাযুক্ত আচরণ প্রদর্শন করছে: সমস্যা


আপনি কোন ব্রাউজারে এটি দেখছেন? ক্রোমে, আমি এটির উদ্দেশ্য কী তা দেখছি।
টেরি

উইন্ডোজের জন্য @ টেরি ফায়ারফক্স .0৩.০ (-৪-বিট)।
রিচার্ড

আপনি কি আপনার প্রশ্নের সাথে এমন একটি জিআইএফ সংযুক্ত করতে পারেন যা সমস্যার বিষয়টি চিত্রিত করে? যতদূর আমি বলতে পারি এটি ফায়ারফক্সে প্রত্যাশা অনুযায়ী রেন্ডারিং / আচরণ করছে।
টেরি

প্রতিশ্রুতি সমাধান হওয়ার পরে, আসল রূপান্তরটি পুনরুদ্ধার করা হয়, তবে এই মুহুর্তে বাক্সটি এখনও রূপান্তরিত হয়। অতএব এটি ফিরে ট্রানজিশন। আসল মানটিতে
ক্রিস জি

একাধিকবার চালানোর সময়, আমি একবার সমস্যা পুনরুত্পাদন করতে পরিচালিত। কম্পিউটার ব্যাকগ্রাউন্ডে কী করছে তার উপর রূপান্তর সম্পাদন নির্ভর করে। প্রতিশ্রুতি সমাধানের আগে বিলম্বের সাথে আরও কিছুটা সময় যুক্ত করা হয়ত সাহায্য করবে।
টিমু

উত্তর:


4

ইভেন্ট লুপ ব্যাচ শৈলীর পরিবর্তন। যদি আপনি একটি লাইনে কোনও উপাদানের স্টাইল পরিবর্তন করেন তবে ব্রাউজারটি তত্ক্ষণাত সেই পরিবর্তনটি প্রদর্শন করে না; এটি পরবর্তী অ্যানিমেশন ফ্রেম পর্যন্ত অপেক্ষা করবে। এই কারণ, উদাহরণস্বরূপ

elm.style.width = '10px';
elm.style.width = '100px';

ঝাঁকুনিতে ফল দেয় না; ব্রাউজারটি সমস্ত জাভাস্ক্রিপ্ট সম্পূর্ণ হওয়ার পরে সেট করা স্টাইলের মানগুলি সম্পর্কে চিন্তা করে।

মাইক্রোটাস্ক সহ সমস্ত জাভাস্ক্রিপ্ট সম্পন্ন হওয়ার পরে রেন্ডারিং ঘটে । একটি প্রতিশ্রুতি একটি microtask ঘটে (যা কার্যকরভাবে তাড়াতাড়ি চালানো হবে অন্য সব জাভাস্ক্রিপ্ট সমাপ্ত হয়েছে, কিন্তু অন্য কিছু করার আগে - রান করার সুযোগ ছিল - যেমন উপস্থাপনা হিসাবে)।.then

ব্রাউজার দ্বারা সৃষ্ট পরিবর্তনটি রেন্ডার করা শুরু করার আগে আপনি যা করছেন তা হ'ল আপনি মাইক্রোটাস্কে transitionসম্পত্তি সেট ''করে দিচ্ছেন style.transform = ''

যদি আপনি কোনও requestAnimationFrame(যা পরের পুনর্নির্মাণের ঠিক আগে চলবে) পরে ফাঁকা স্ট্রিংয়ে স্থানান্তরটি পুনরায় সেট করেন এবং তারপরে একটি setTimeout(যা পরের পুনর্নির্মাণের ঠিক পরে চলবে), এটি প্রত্যাশা অনুযায়ী কাজ করবে:

const box = document.querySelector('.box')
box.addEventListener('click', e => {
  if (!box.style.transform) {
    box.style.transform = 'translateX(100px)'
    setTimeout(() => {
      box.style.transition = 'none'
      box.style.transform = ''
      // resolve('Transition complete')
      requestAnimationFrame(() => {
        setTimeout(() => {
          box.style.transition = ''
        });
      });
    }, 2000)
  }
})
.box {
  width: 100px;
  height: 100px;
  border-radius: 5px;
  background-color: #121212;
  transition: all 2s ease;
}
<div class="box"></div>


এই উত্তরটি আমি খুঁজছিলাম। ধন্যবাদ। আপনি, সম্ভবত, একটি লিঙ্ক সরবরাহ করতে পারেন যা এই মাইক্রোটাস্ক এবং মেকানিক্সটিকে পুনরায় রঙ করতে পারে ?
রিচার্ড

এটি দেখতে একটি ভাল সংক্ষিপ্তসার মতো দেখাচ্ছে: javascript.info/event-loop
CertainPerformance

2
এটি ঠিক সত্য নয়। ইভেন্টের লুপটি শৈলীর পরিবর্তন সম্পর্কে কিছু বলে না। বেশিরভাগ ব্রাউজারগুলি যখন পারে তখন তারা পরবর্তী চিত্রের ফ্রেমের জন্য অপেক্ষা করার চেষ্টা করবে তবে এটি প্রায় about আরও তথ্য ;-)
কাইডো

3

আপনি রূপান্তরের বিভিন্নতার মুখোমুখি হচ্ছেন যদি উপাদান লুকানো সমস্যা শুরু করে তবে সরাসরি transitionসম্পত্তিতে কাজ করে না

"Redraw" প্রক্রিয়াটির জন্য CSSOM এবং DOM কীভাবে সংযুক্ত রয়েছে তা বুঝতে আপনি এই উত্তরটি উল্লেখ করতে পারেন ।
মূলত, ব্রাউজারগুলি পরবর্তী পেইন্টিং ফ্রেম পর্যন্ত সমস্ত নতুন বাক্স পজিশন পুনরায় গণনা করতে এবং এভাবে সিএসএসএমে সিএসএস বিধি প্রয়োগ করার জন্য অপেক্ষা করবে।

তোমার প্রতিজ্ঞা হ্যান্ডলার তাই, যখন আপনি রিসেট transitionকরতে "", transform: ""এখনো হিসাব করা হয়নি। যখন এটি গণনা করা transitionহবে, ইতোমধ্যে পুনরায় সেট হয়ে গেছে ""এবং CSSOM ট্রান্সফর্ম আপডেটের জন্য ট্রানজিশনটিকে ট্রিগার করবে।

তবে, আমরা ব্রাউজারকে "রিফ্লো" ট্রিগার করতে বাধ্য করতে পারি এবং এভাবে রূপান্তরটি পুনরায় সেট করার আগে আমরা এটিটিকে আপনার উপাদানটির অবস্থান পুনরায় গণনা করতে পারি ""

যা প্রতিশ্রুতিটি ব্যবহার করা বেশ অপ্রয়োজনীয় করে তোলে:

const box = document.querySelector('.box')
box.addEventListener('click', e => {
  if (!box.style.transform) {
    box.style.transform = 'translateX(100px)'
    setTimeout(() => {
      box.style.transition = 'none'
      box.style.transform = ''
      box.offsetWidth; // this triggers a reflow
      // even synchronously
      box.style.transition = ''
    }, 2000)
  }
})
.box {
  width: 100px;
  height: 100px;
  border-radius: 5px;
  background-color: #121212;
  transition: all 2s ease;
}
<div class = "box"></div>


এবং মাইক্রো-টাস্কগুলির মত ব্যাখ্যা Promise.resolve()বা মিউটেশনএভেন্টস সম্পর্কে ব্যাখ্যা করার জন্য , বা queueMicrotask()আপনাকে বুঝতে হবে যে বর্তমান টাস্কটি শেষ হওয়ার সাথে সাথে তারা ছুটে আসবে, রেন্ডারিং পদক্ষেপগুলির আগে ইভেন্ট-লুপ প্রসেসিং মডেলের 7 ম পদক্ষেপ
সুতরাং আপনার ক্ষেত্রে এটি খুব ভালো লাগে যদি এটি সিঙ্ক্রোনালি চালিত হয়।

যাইহোক, সাবধানী মাইক্রো-কার্যগুলি কিছুক্ষণের লুপের মতো ব্লক করা যেতে পারে:

// this will freeze your page just like a while(1) loop
const makeProm = ()=> Promise.resolve().then( makeProm );

হ্যাঁ ঠিকই, তবে transitionendইভেন্টটির প্রতিক্রিয়াটি উত্তরণের শেষের সাথে ম্যাচ করার জন্য হার্ড-কোড হওয়া একটি টাইমআউট হওয়া এড়াতে পারে। TransitionToPromise.js আপনাকে লেখার অনুমতি দেয় এমন রূপান্তরটি প্রচার করবে transitionToPromise(box, 'transform', 'translateX(100px)').then(() => /* four lines as per answer above */)
রোমের -1888

দুটি সুবিধা: (1) উত্তরণের সময়কাল জাভাস্ক্রিপ্ট পরিবর্তন করার প্রয়োজন ছাড়াই সিএসএসে সংশোধন করা যেতে পারে; (২) ট্রানজিশনটোপ্রিমাইজ.জেএস পুনরায় ব্যবহারযোগ্য। বিটিডাব্লু, আমি চেষ্টা করেছিলাম এবং এটি ভাল কাজ করে।
রোমের -1888

@ (evt)=>if(evt.propertyName === "transform"){ ...রোমের -১৮৮ you হ্যাঁ আপনি করতে পারেন, যদিও আমি ব্যক্তিগতভাবে মিথ্যা ইতিবাচকতা এড়াতে একটি চেক যোগ করতে পারি এবং আমি এই জাতীয় ঘটনার প্রতিশ্রুতি দেওয়া সত্যিই পছন্দ করি না, কারণ আপনি কখনই জানেন না যে এটি কখন আগুনে ছড়িয়ে পড়েছে ( someAncestor.hide() রূপান্তরটি চলার সময় এমন কেস সম্পর্কে ভাবুন , তোমার প্রতিজ্ঞা কখনো অগ্নি ও আপনার স্থানান্তর আটকে যান করবে অক্ষম সুতরাং যে কি তাদের জন্য সবচেয়ে ভাল, কিন্তু ব্যক্তিগতভাবে ও অভিজ্ঞতার ভিত্তিতে নির্ধারণ করতে ওপি সত্যিই আপ, আমি এখন transitionend ঘটনা চেয়ে সময় সমাপ্ত পছন্দ
Kaiido

1
পেশাদাররা এবং কনস, আমার ধারণা। যাই হোক না কেন, প্রতিশ্রুতি সহ বা ছাড়াই, এই উত্তর দুটি সেটটাইমআউট এবং একটি অনুরোধঅ্যানিমেশনফ্রেমের সাথে জড়িত তার চেয়ে অনেক বেশি পরিষ্কার।
রোমের -1888

যদিও আমার একটা প্রশ্ন আছে। আপনি বলেছিলেন যে পরবর্তী ব্রাউজারটি পুনরায় রঙ করার ঠিক আগেrequestAnimationFrame() ট্রিগার করা হবে । আপনি আরও উল্লেখ করেছেন যে ব্রাউজারগুলি পরবর্তী পেইন্টিং ফ্রেম পর্যন্ত সমস্ত নতুন বাক্স অবস্থান পুনরায় গণনা করতে অপেক্ষা করবে । তবুও, আপনাকে এখনও জোর করে রিফ্লোটি ম্যানুয়ালি ট্রিগার করতে হবে (প্রথম লিঙ্কটিতে আপনার উত্তর)। আমি তাই উপসংহার এমনকি যখন আঁকা শুধু নূতনে রঙ সামনে ঘটে, ব্রাউজার এখনো করেনি না নবীনতম কম্পিউটেড শৈলী হিসাব; সুতরাং, ম্যানুয়ালি স্টাইলগুলির পুনঃ গণনামূলকভাবে বাধ্য করার প্রয়োজন । সঠিক? requestAnimationFrame()
রিচার্ড

0

আমি কৃতজ্ঞ যে এটি আপনি যা খুঁজছেন তা পুরোপুরি নয়, তবে - কৌতূহল এবং সম্পূর্ণতার জন্য - আমি দেখতে চেয়েছিলাম যে আমি এই প্রভাবের জন্য কোনও সিএসএস-কেবল পন্থা লিখতে পারি কিনা।

প্রায় ... তবে দেখা যাচ্ছে যে আমাকে এখনও জাভাস্ক্রিপ্টের একটি লাইন অন্তর্ভুক্ত করতে হয়েছিল।

কাজের উদাহরণ:

document.querySelector('.box').addEventListener('animationend', (e) => e.target.blur());
.box {
  width: 100px;
  height: 100px;
  border-radius: 5px;
  background-color: #121212;
  cursor: pointer;
}

.box:focus {
 animation: boxAnimation 2s ease;
}

@keyframes boxAnimation {
  100% {transform: translateX(100px);}
}
<div class="box" tabindex="0"></div>


-1

আমি বিশ্বাস করি আপনার সমস্যার মাত্র থাকেন তবে আপনার মধ্যে .thenআপনি সেটিং করা হয় transitionথেকে '', যখন আপনি এটি সেটিং করতে হবে noneআপনি টাইমার কলব্যাক মধ্যে করেনি।

const box = document.querySelector('.box');
box.addEventListener('click', e => {
  if (!box.style.transform) {
    box.style.transform = 'translateX(100px)';
    new Promise(resolve => {
      setTimeout(() => {
        box.style.transition = 'none';
        box.style.transform = '';
        resolve('Transition complete');
      }, 2000)
    }).then(() => {
     box.style.transition = 'none'; // <<----
    })
  }
})
.box {
  width: 100px;
  height: 100px;
  border-radius: 5px;
  background-color: #121212;
  transition: all 2s ease;
}
<div class = "box"></div>


1
না, ওপি ''পুনরায় শ্রেণি বিধি প্রয়োগ করার জন্য এটি সেট করে দিচ্ছে (যা উপাদান বিধি দ্বারা বাতিল করা হয়েছিল) আপনার কোডটি কেবল এটি 'none'দ্বিগুণ করে সেট করে , যা বাক্সটিকে ফিরে স্থানান্তরিত হতে বাধা দেয় তবে তার আসল রূপান্তর (শ্রেণীর) পুনরুদ্ধার করে না
ক্রিস জি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.