2015-12-26 34 views
7

Giả sử tôi có phần tử SVG có đường dẫn cho tất cả các tiểu bang của Hoa Kỳ.Tạo thành phần SVG tương tác bằng React

<svg> 
    <g id="nh"> 
     <title>New Hampshire</title> 
     <path d="m 880.79902,142.42476 0.869,-1.0765 1.09022,..." id="NH" class="state nh" /> 
    </g> 
    ... 
</svg> 

Dữ liệu SVG được lưu trong một tệp riêng biệt với tiện ích mở rộng .svg. Giả sử tôi muốn tạo thành phần React của bản đồ đó, với toàn quyền kiểm soát nó để tôi có thể sửa đổi kiểu dáng của từng trạng thái dựa trên một số đầu vào bên ngoài.

Sử dụng Webpack, như xa như tôi có thể nói, tôi có hai tùy chọn cho tải đánh dấu SVG: Chèn nó như đánh dấu liệu bằng cách sử dụng raw-loader và tạo ra một thành phần sử dụng dangerouslySetInnerHTML:

var InlineSvg = React.createClass({ 
    render() { 
    var svg = require('./' + this.props.name + '.svg'); 
    return <div dangerouslySetInnerHTML={{__html: svg}}></div>; 
    } 
}); 

hoặc tự chuyển đổi đánh dấu vào JSX hợp lệ:

var NewComponent = React.createClass({ 
    render: function() { 
    return (
     <svg> 
      <g id="nh"> 
       <title>New Hampshire</title> 
       <path d="m 880.79902,142.42476 0.869,-1.0765 1.09022,..." id="NH" className="state nh" /> 
      </g> 
      ... 
     </svg> 
    ); 
}); 

Cuối cùng, giả sử ngoài bản đồ SVG, có một danh sách HTML đơn giản về tất cả các trạng thái. Bất cứ khi nào người dùng di chuột qua mục danh sách, đường dẫn SVG tương ứng sẽ thay đổi màu tô.

Bây giờ, điều tôi dường như không thể tìm ra là cách cập nhật thành phần React SVG để phản ánh trạng thái được di chuột. Chắc chắn, tôi có thể tiếp cận vào DOM, chọn trạng thái SVG theo tên lớp và thay đổi màu của nó, nhưng điều đó dường như không phải là cách "phản ứng" để làm điều đó. Một ngón tay trỏ sẽ được nhiều đánh giá cao.

PS. Tôi đang sử dụng Redux để xử lý tất cả các giao tiếp giữa các thành phần.

Trả lời

3

Bạn cần phải làm hai việc:

1) Thiết lập một event listener trên mỗi mục để thông báo cho ứng dụng của bạn trong những mục được đánh dấu.

<li 
    onMouseOver={() => this.handleHover('NH')} 
    onMouseOut={() => this.handleUnhover()} 
> 
    New Hampshire 
</li> 

2) Ghi lại dữ liệu và truyền nó thành thành phần SVG của bạn.

Đây là phần phức tạp hơn và nó hướng đến cách bạn đã cấu trúc ứng dụng của mình.

  • Nếu toàn bộ ứng dụng của bạn là một Phản ứng thành phần duy nhất, sau đó handleHover sẽ chỉ cần cập nhật trạng thái thành phần
  • Nếu ứng dụng của bạn được chia thành nhiều thành phần, sau đó handleHover sẽ kích hoạt callback thông qua tại như một chỗ dựa

Giả sử sau. Các phương pháp thành phần có thể trông như thế này:

handleHover(territory) { 
    this.props.onHighlight(territory); 
} 

handleUnhover() { 
    this.props.onHighlight(null); 
} 

Giả sử bạn có một bộ phận phụ huynh, trong đó có cả bản đồ SVG và danh sách, nó có thể trông giống như thế này:

class MapWrapper extends React.Component { 

    constructor(props) { 
     super(props); 
     this.state = { 
      highlighted: null; 
     }; 
    } 

    setHighlight(territory) { 
     this.setState({ 
      highlighted: territory 
     }); 
    } 

    render() { 
     const highlighted = { this.state }; 
     return (
      <div> 
       <MapDiagram highlighted={highlighted} /> 
       <TerritoryList onHighlight={(terr) => this.setHighlight(terr)} /> 
      </div> 
     ); 
    } 

} 

Mấu chốt ở đây là biến trạng thái highlighted. Mỗi lần xảy ra sự kiện di chuột mới, highlighted thay đổi về giá trị. Thay đổi này kích hoạt tái xuất hiện và giá trị mới được chuyển vào , sau đó có thể xác định phần nào của SVG cần đánh dấu.

+0

Trông tuyệt vời, cảm ơn! Mặc dù vậy, một điều 'lãnh thổ 'chính trong đối tượng trạng thái trong' setHighlight' sẽ được' tô sáng' đúng không?Vì vậy, đó là phù hợp với tên khóa trong đối tượng trạng thái ban đầu. –

+0

Điểm tốt. Đã sửa. –

+1

Đối với phần "tuyên truyền cho SVG", tôi đã tạo https://www.npmjs.com/package/react-samy-svg. Nó giúp dễ dàng tải và thao tác các thuộc tính phần tử svg. –

Các vấn đề liên quan