跳至內容
Astera Technology

動作完成不能只等動畫結束

沒有動畫時,也沿動作結果更新。

下載完整個案資料及參考答案 ↓

訂判斷及所需輸入

真正 CSS 在 prefers-reduced-motion 停動畫。錯處理等 animationend,令題內已完成動作仍 processing;更正沿所附動作 Promise,結果可完成、失敗或未明。

已填本地測試工作表
情況輸入 JSON
原例測試{"motion":"reduce","outcome":"completed"}
下載可編輯 CSV ↓

跑所附比較

瀏覽器真正套兩種動畫偏好並執行處理;標記只屬本地假設動作,動畫完未證明外部業務成功。

錯誤及所需輸出
路徑輸出 JSON
錯誤路徑{"state":"processing"}
所需路徑{"state":"completed"}
下載可編輯 CSV ↓
Node24.14.1 程序;須 Playwright1.63 Chromium
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
const htmlEscape=s=>String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
async function withPage(action,options={}){
  const require=createRequire(import.meta.url);const {chromium}=require('playwright');
  const browser=await chromium.launch({headless:true});
  try{const context=await browser.newContext(options);const page=await context.newPage();
    const requests=[];await page.route('**/*',route=>{requests.push(route.request().url());return route.abort();});
    return await action(page,context,requests);
  }finally{await browser.close();}
}

const run=async function run(i,corrected=true){
    if(!['completed','failed','unknown'].includes(i.outcome)||!['normal','reduce'].includes(i.motion))return {held:true};
    return withPage(async page=>{await page.setContent('<style>.animate{animation:pulse 10ms linear}@keyframes pulse{to{opacity:.5}}@media(prefers-reduced-motion:reduce){.animate{animation:none}}</style><div class="progress">Working</div><output id="state">processing</output>');
      await page.evaluate(({corrected,outcome})=>{const state=document.querySelector('#state');if(corrected)Promise.resolve(outcome).then(result=>state.textContent=result);else document.querySelector('.progress').addEventListener('animationend',()=>state.textContent='completed');document.querySelector('.progress').classList.add('animate');},{corrected,outcome:i.outcome});
      if(corrected||i.motion==='normal')await page.waitForFunction(()=>document.querySelector('#state').textContent!=='processing',{timeout:2000});
      return {state:await page.locator('#state').textContent()};
    },{reducedMotion:i.motion==='reduce'?'reduce':'no-preference'});
  };
const cases=[{"input":{"motion":"reduce","outcome":"completed"},"corrected":false,"expected":{"state":"processing"}},{"input":{"motion":"reduce","outcome":"completed"},"corrected":true,"expected":{"state":"completed"}},{"input":{"motion":"normal","outcome":"completed"},"corrected":true,"expected":{"state":"completed"}},{"input":{"motion":"reduce","outcome":"failed"},"corrected":true,"expected":{"state":"failed"}},{"input":{"motion":"reduce","outcome":"unknown"},"corrected":true,"expected":{"state":"unknown"}}];
for(const test of cases){const actual=await run(test.input,test.corrected);assert.deepEqual(actual,test.expected);console.log(actual);}
下載可執行例子 ↓

按邊界依據作判斷

正常動畫配完成結果可到 completed;減動畫時 failed、unknown 仍各自保留。

  1. 套所需動畫偏好
  2. 取動作本身結果
  3. 更新有名稱的狀態

不能把失敗或未明動作改成視覺成功。

可編輯邊界輸入及結果
條件輸入 JSON預期輸出 JSON
正常動畫下的動作{"motion":"normal","outcome":"completed"}{"state":"completed"}
真正結果為失敗{"motion":"reduce","outcome":"failed"}{"state":"failed"}
真正結果仍未明{"motion":"reduce","outcome":"unknown"}{"state":"unknown"}
下載可編輯 CSV ↓

原例更正後,甚麼驅動完成?

查看參考答案

所附動作結果。animationend 可不出現,不能是唯一完成訊號。

相關資源