当DOM元素的计算样式发生变化时触发事件?

时间:2012-11-01 22:23:09

标签: javascript css dom

是否有非民意方法来监听元素computed style的更改?

这个幻想代码片段应该简洁地解释我的意思:

var el = document.getElementById('doodad');

el.addComputedStyleChangeListener('width', function (prev, new) {
  alert('Previous width: ' + prev + '; New width: ' + new);
});

我知道DOMAttrModified突变事件和即将发生的MutationObserver,但两者都不够 - 它们只能用于观察元素的style DOM属性,它并不完全确定元素的计算样式。


用于此的用例最初是this question的一部分,这真的只会引起我的好奇心。

2 个答案:

答案 0 :(得分:4)

没有这样的方法。 CSS OM还没有。

目前尚不清楚"计算出的风格变化"装置

原则上,您可以检测已使用(例如渲染)样式的更改。但这需要 像" paint"或"布局"即将发生。

答案 1 :(得分:0)

目前你能做的最好的就是请求动画帧。

getComputedStyle显然会返回计算属性的实时更新对象。

你可以像这样做一个基本的动画循环:

var computedStyle = getComputedStyle(element);
var animate = function () {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = computedStyle.color;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    requestAnimationFrame(animate);
};
animate();

如果任何已使用的属性发生更改,您可以通过仅更新进行优化:

var computedStyle = getComputedStyle(element);
var lastFrameBackground;
var lastFrameColor;
var animate = function () {
    if (
        computedStyle.background !== lastFrameBackground ||
        computedStyle.color !== lastFrameColor
    ) {
       lastFrameBackground = computedStyle.background;
       lastFrameColor = computedStyle.color;

       // assuming expensive drawing code here
       // not like this!
       ctx.clearRect(0, 0, canvas.width, canvas.height);
       ctx.fillStyle = computedStyle.color;
       ctx.fillRect(0, 0, canvas.width, canvas.height);
    }
    requestAnimationFrame(animate);
};
animate();

如果是针对特定的CSS动画,您可以通过聆听requestAnimationFrameanimationstart来管理animationend循环,或者如果这些事件不合适有足够的浏览器支持,你可以在你知道动画开始时(例如mouseenter:hover)启动它,并在动画属性的计算值停止变化时停止(即不要&# 39;如果requestAnimationFrame等于之前的值,则调用setInterval

如果您不需要动画制作动画,可以使用requestAnimationFrame获得更好的效果(检查文档是否隐藏var computedStyle = getComputedStyle(element); setInterval(function () { if (!document.hidden) { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = computedStyle.color; ctx.fillRect(0, 0, canvas.width, canvas.height); } }, 200); 隐式执行的操作:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Grid1 g = myCanvas.CreateGrid();
            ContentControl1 cc = myCanvas.CreateCC();
            Button1 b = myCanvas.CreateButton1();

            Grid1.SetColumn(cc, 0);
            Grid1.SetRow(cc, 0);
            Grid1.SetColumn(b, 1);
            Grid1.SetRow(b, 1);
            g.Children.Add(cc);
            g.Children.Add(b);

            Canvas1.SetLeft(g, 500);
            Canvas1.SetTop(g, 5);
            myCanvas.Children.Add(g);
        }

    }

    public class Button1 : Button
    {

        protected override void OnClick()
        {

            Grid1 old_g = (Grid1)VisualTreeHelper.GetParent(this as DependencyObject);
            Canvas1 cnv = (Canvas1)VisualTreeHelper.GetParent(old_g as DependencyObject);
            Grid1 g = cnv.CreateGrid();
            ContentControl1 cc = cnv.CreateCC();
            Button1 b = cnv.CreateButton1();

            Grid1.SetColumn(cc, 0);
            Grid1.SetRow(cc, 0);
            Grid1.SetColumn(b, 1);
            Grid1.SetRow(b, 1);
            g.Children.Add(cc);
            g.Children.Add(b);

            Canvas1.SetLeft(g, 500);
            Canvas1.SetTop(g, cnv.Children.Count * 120);
            cnv.Children.Add(g);

            cnv.ConnectGrids(old_g, g);
        }


    }

    public class Canvas1 : Canvas
    {
        public Grid1 CreateGrid()
        {
            Grid1 g = new Grid1() { Width = 100, Height = 20, Background = Brushes.White };
            g.HorizontalAlignment = HorizontalAlignment.Center;
            g.VerticalAlignment = VerticalAlignment.Center;
            g.ShowGridLines = false;

            ColumnDefinition colDef1 = new ColumnDefinition();
            ColumnDefinition colDef2 = new ColumnDefinition() { Width = new GridLength(20) };
            g.ColumnDefinitions.Add(colDef1);
            g.ColumnDefinitions.Add(colDef2);

            RowDefinition rowDef1 = new RowDefinition();
            g.RowDefinitions.Add(rowDef1);
            return g;
        }

        public ContentControl1 CreateCC()
        {
            ContentControl1 cc = new ContentControl1()
            {
                VerticalContentAlignment = VerticalAlignment.Stretch,
                HorizontalContentAlignment = HorizontalAlignment.Stretch,
                BorderBrush = Brushes.BlueViolet,
            };
            return cc;
        }

        public Button1 CreateButton1()
        {
            Button1 b = new Button1()
            {
                VerticalContentAlignment = VerticalAlignment.Stretch,
                HorizontalContentAlignment = HorizontalAlignment.Stretch,
                BorderBrush = Brushes.Red
            };
            return b;
        }

        public void ConnectGrids(Grid1 g1, Grid1 g2)
        {
            Canvas1 cnv = (Canvas1)VisualTreeHelper.GetParent(g1 as DependencyObject);
            Transform transform1 = (Transform)g1.TransformToVisual(cnv as Visual);
            Transform transform2 = (Transform)g2.TransformToVisual(cnv as Visual);

            Point StartPoint1 = transform1.Transform(new Point(g1.Width, g1.Height / 2.0));
            Point EndPoint1 = transform2.Transform(new Point(g2.Width, g2.Height / 2.0));


            var lineGeometry = new LineGeometry()
            {
                StartPoint = StartPoint1,
                EndPoint = EndPoint1
            };

            var path = new Path()
            {
                Data = lineGeometry,
                Stroke = new SolidColorBrush(Colors.Black),
            };

            cnv.Children.Add(path);

        }

    }

    public class ContentControl1 : ContentControl
    {

    }

    public class Grid1 : Grid
    {

    }


}