Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/hadoop/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elm boundingClientRect获取元素相对于文档的位置_Elm - Fatal编程技术网

Elm boundingClientRect获取元素相对于文档的位置

Elm boundingClientRect获取元素相对于文档的位置,elm,Elm,我正在尝试实现一个拖放程序,使用DOM包中的boundingClientRect获取要移动的元素的尺寸,并使用鼠标中的position跟踪鼠标在拖动时的移动 在我滚动之前,程序运行良好,但当我向下滚动时,拖动元素在视图中的显示高度高于单击它之前的显示高度。我怀疑发生的是,boundingClientRect获取元素相对于视点的位置,然后我使用这些值设置top和left值。但是,top和left与文档或父元素相关。但是,我不知道我可以使用什么来代替或补充boundingClientRect,以获得

我正在尝试实现一个拖放程序,使用DOM包中的
boundingClientRect
获取要移动的元素的尺寸,并使用鼠标中的
position
跟踪鼠标在拖动时的移动

在我滚动之前,程序运行良好,但当我向下滚动时,拖动元素在视图中的显示高度高于单击它之前的显示高度。我怀疑发生的是,
boundingClientRect
获取元素相对于视点的位置,然后我使用这些值设置
top
left
值。但是,
top
left
与文档或父元素相关。但是,我不知道我可以使用什么来代替或补充
boundingClientRect
,以获得相对于文档或父元素的
left
top

这是代码,可能比我的漫无边际更清楚

type alias Model =
    { movableItemsList : List Item
    , originalMovableItems : List Item
    , movingItem : Maybe ( Item, Rectangle )
    , receivingItemsList : List Item
    , updatedItemsList : List ( Item, Rectangle )
    , drag : Maybe Drag
    , scrollTop : Float
    }

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        DragAndDelete deleteMsg xy movingItem movingRectangle ->
            model
                ! [ command (DragStart xy movingItem movingRectangle)
                  , command (deleteMsg movingItem)
                  ]

        DragStart xy selectedItem movingRectangle ->
            let
                movingItem =
                    List.head (List.filter (\i -> i.id == selectedItem.id) model.originalMovableItems)
                        |> Maybe.withDefault (Item "" "" 0 "")
            in
                { model
                    | drag = Just (Drag xy xy)
                    , movingItem = Just ( movingItem, movingRectangle )
                }
                    ! []

        DragAt xy ->
            { model
                | drag =
                    (Maybe.map (\{ start } -> Drag start xy) model.drag)
            }
                ! []

        DragEnd _ ->
            { model
                | movingItem = Nothing
                , drag = Nothing
            }
                ! []

        DeleteFromUpdatedList movingItem ->
            let
                isKeepable iteratingItem =
                    iteratingItem.id /= movingItem.id

                updatedItemsData =
                    List.filter (\( i, _ ) -> isKeepable i) model.updatedItemsList
            in
                { model
                    | updatedItemsList = updatedItemsData
                }
                    ! []

        DeleteFromMovableList movingItem ->
            let
                isKeepable iteratingItem =
                    iteratingItem.id /= movingItem.id

                movableItemsData =
                    List.filter isKeepable model.movableItemsList
            in
                { model
                    | movableItemsList = movableItemsData
                }
                    ! []

        UpdateReceivingItemsOnOverlap receivingRectangle receivingItem ->
            let
                receivingItemsData =
                    if (checkOverlap (getCurrentMovingRectangle model) receivingRectangle) then
                        List.map (\i -> updateItemColor i receivingItem) model.receivingItemsList
                    else
                        model.receivingItemsList
            in
                { model | receivingItemsList = receivingItemsData } ! []

        RestoreReceivingItemsListColor _ ->
            let
                receivingItemsData =
                    List.map restoreReceivingItemColor model.receivingItemsList
            in
                { model | receivingItemsList = receivingItemsData } ! []

        AddValues receivingRectangle receivingItem ->
            let
                movingItem =
                    movingItemMaybe model.movingItem

                updatedItemsData =
                    if (checkOverlap (getCurrentMovingRectangle model) receivingRectangle) then
                        ( { movingItem
                            | value = receivingItem.value + movingItem.value
                            , color = "#1A6B0D"
                          }
                        , receivingRectangle
                        )
                            :: model.updatedItemsList
                    else
                        model.updatedItemsList
            in
                { model
                    | updatedItemsList = updatedItemsData
                }
                    ! [ command (DeleteFromMovableList movingItem)
                      ]

        RestoreListContent ->
            let
                movingItem =
                    movingItemMaybe model.movingItem

                listItems =
                    movingItem :: model.movableItemsList
            in
                { model | movableItemsList = listItems } ! []


getCurrentMovingRectangle : Model -> Rectangle
getCurrentMovingRectangle model =
    let
        movingItemTuple =
            Maybe.withDefault ( Item "" "" 0 "0", Rectangle 0 0 0 0 ) model.movingItem

        ( _, movingRect ) =
            movingItemTuple
    in
        case model.drag of
            Nothing ->
                movingRect

            Just { start, current } ->
                Rectangle
                    (movingRect.top + toFloat (current.y - start.y))
                    (movingRect.left + toFloat (current.x - start.x))
                    (movingRect.width)
                    (movingRect.height)



-- VIEW


view : Model -> Html Msg
view model =
    div
        []
        [ receivingAndUpdatedItemsLayersDiv model
        , movableItemsListDiv model
        , if model.movingItem /= Nothing then
            movingItemDiv model
          else
            div [] []
        ]


receivingAndUpdatedItemsLayersDiv : Model -> Html Msg
receivingAndUpdatedItemsLayersDiv model =
    div
        [ style [ ( "position", "relative" ) ] ]
        [ div
            [ style
                [ ( "position", "relative" )
                , ( "top", "10px" )
                , ( "left", "80px" )
                ]
            ]
            [ div
                [ style
                    [ ( "z-index", "3" )
                    , ( "position", "absolute" )
                    ]
                , attribute "class" "drag-here-overlay"
                ]
                (List.map receivingItemOverlay model.receivingItemsList)
            , div
                [ style
                    [ ( "z-index", "0" )
                    , ( "position", "absolute" )
                    ]
                , attribute "class" "drag-here-underlay"
                ]
                (List.map receivingItemUnderlay model.receivingItemsList)
            ]
        , div
            []
            [ div
                [ style
                    [ ( "position", "absolute" )
                    , ( "z-index", "1" )
                    ]
                , attribute "class" "drag-here-updated"
                ]
                (List.map updatedItemUnderlay model.updatedItemsList)
            , div
                [ style
                    [ ( "position", "absolute" )
                    , ( "z-index", "4" )
                    ]
                ]
                (List.map updatedItemOverlay model.updatedItemsList)
            ]
        ]


movableItemsListDiv : Model -> Html Msg
movableItemsListDiv model =
    div
        [ style
            [ ( "position", "relative" )
            , ( "top", "10px" )
            , ( "left", "800px" )
            ]
        ]
        (List.map movableItemDiv model.movableItemsList)


updatedItemUnderlay : ( Item, Rectangle ) -> Html Msg
updatedItemUnderlay ( item, rectangle ) =
    div
        [ attribute "class" "drag-here-updated-underlay-item"
        , sharedStyles
        , style
            [ ( "background-color", item.color )
            , ( "border", "1px solid #000" )
            , ( "position", "absolute" )
            , ( "left", px rectangle.left )
            , ( "top", px rectangle.top )
            ]
        ]
        [ text item.text
        , br [] []
        , text (toString item.value)
        ]


updatedItemOverlay : ( Item, Rectangle ) -> Html Msg
updatedItemOverlay ( item, rectangle ) =
    div
        [ onDragStart DeleteFromUpdatedList item
        , attribute "class" "drag-here-updated-overlay-item"
        , sharedStyles
        , style
            [ ( "background-color", "transparent" )
            , ( "position", "absolute" )
            , ( "left", px rectangle.left )
            , ( "top", px rectangle.top )
            ]
        ]
        []


receivingItemUnderlay : Item -> Html Msg
receivingItemUnderlay item =
    div
        [ attribute "class" "drag-here-underlay-item"
        , sharedStyles
        , style
            [ ( "background-color", item.color )
              -- , ( "border", "1px solid #1A6B0D" )
            ]
        ]
        [ text item.text
        , br [] []
        , text (toString item.value)
        ]


receivingItemOverlay : Item -> Html Msg
receivingItemOverlay item =
    div
        [ on "mouseenter" (Decode.map (\d -> UpdateReceivingItemsOnOverlap d item) (DOM.target DOM.boundingClientRect))
        , on "mouseleave" (Decode.map (\d -> RestoreReceivingItemsListColor d) (DOM.target DOM.boundingClientRect))
        , on "mouseup" (Decode.map (\d -> AddValues d item) (DOM.target DOM.boundingClientRect))
        , attribute "class" "drag-here-overlay-item"
        , sharedStyles
        , style
            [ ( "background-color", "transparent" ) ]
        ]
        []


movableItemDiv : Item -> Html Msg
movableItemDiv item =
    div
        [ onDragStart DeleteFromMovableList item
        , attribute "id" ("drag-me " ++ toString item.value)
        , sharedStyles
        , style
            [ ( "background-color", item.color )
            , ( "border", "1px solid #DD0848" )
            , ( "position", "relative" )
            ]
        ]
        [ text "Drag Me!"
        , br [] []
        , text (toString item.value)
        ]


movingItemDiv : Model -> Html Msg
movingItemDiv model =
    let
        movingItem =
            movingItemMaybe model.movingItem

        realRectangle =
            getCurrentMovingRectangle model
    in
        div
            [ onMouseUp RestoreListContent
            , sharedStyles
            , style
                [ ( "background-color", "#FF3C8C" )
                , ( "border", "1px solid #DD0848" )
                , ( "position", "absolute" )
                , ( "top", px (realRectangle.top) )
                , ( "left", px (realRectangle.left) )
                , ( "z-index", "2" )
                ]
            ]
            [ text movingItem.text
            , br [] []
            , text (toString movingItem.value)
            ]


sharedStyles : Attribute a
sharedStyles =
    style
        [ ( "width", "100px" )
        , ( "height", "100px" )
        , ( "border-radius", "4px" )
        , ( "color", "white" )
        , ( "justify-content", "center" )
        , ( "align-items", "center" )
        , ( "display", "flex" )
        ]


onDragStart : (Item -> Msg) -> Item -> Attribute Msg
onDragStart deleteMsg item =
    on "mousedown"
        (Mouse.position
            `Decode.andThen`
                (\posit ->
                    DOM.target DOM.boundingClientRect
                        `Decode.andThen`
                            (\rect ->
                                Decode.succeed (DragAndDelete deleteMsg posit item rect)
                            )
                )
        )


px : countable -> String
px number =
    toString number ++ "px"
因此,如您所见,当您单击
movableItemDiv
时,模型的
drag
movableItem
字段将分别使用鼠标位置和
movableItem
的尺寸(矩形)进行更新。但是,这些尺寸是相对于视点的
movingItemDiv
然后调用
getCurrentMovingRectangle
,根据模型中的
movingItem
拖动
的尺寸,设置
movingItemDiv
左侧和
top
样式。因为
movingItem
的尺寸基于
movableItemDiv
相对于视点的尺寸,而不是相对于文档的尺寸,而
movingItemDiv
顶部和
左侧的
值设置的值建立了元素相对于文档的位置(或者是父元素,老实说,我不确定),
movingItemDiv
的位置不正确。我希望这是清楚的!

更新为elm-0.18

下面是一个包含可拖动项的列表的快速而肮脏的示例

(您可以将其复制到以查看其运行情况)

  • 每个项目都有一个相对定位
  • transform:translate()
    用于定位要拖动的项
  • 我们不知道物品的绝对位置,但我们知道它相对于(未知)起始位置移动了多少
下一步是确定当拖动结束时,我们是否在下降区上方。 要进行计算,您需要知道:

  • 放置区域相对于列表容器左上角的相对位置
  • 每个下降区的大小(宽度、高度)
  • 相对于列表容器左上角拖动的项的原始位置
    • 为此,您需要知道每个项目的实际高度(我总是在每个项目上使用固定高度)
  • 列表容器中的滚动量(使用elm lang/Dom中的Dom.y)
希望这将帮助你在正确的方向

导入Html公开(…)
导入Html.Attributes(..)
导入Html.Events(打开)
导入Json。解码为Json
导入鼠标(位置)
主要=
Html.program
{init=init
,视图=视图
,update=update
,订阅=订阅
}
--模型
类型别名模型=
{位置:位置
,项:列表字符串
拖拉:也许拖拉
}
类型别名拖动=
{id:Int
,开始:位置
,现时:职位
}
初始化:(模型,Cmd Msg)
初始化=
模型
(职位200)
[“苹果”、“香蕉”、“樱桃”、“爸爸”]
没有什么
! []
--更新
输入味精
=DragStart Int位置
|德拉格位置
|德拉根位置
更新:Msg->Model->(Model,Cmd-Msg)
更新msg模型=
(更新帮助消息模型,Cmd.none)
更新帮助:Msg->Model->Model
updateHelp msg({位置,项目,拖动}作为模型)=
味精案例
DragStart id xy->
模型位置项目(仅(拖动id xy))
DragAt xy->
模型位置项(Maybe.map(\{id,start}->Drag id start xy)拖动)
德拉根德->
模型位置项目无
--订阅
订阅:模型->子消息
订阅模式=
案例模型
没有->
无
只是-->
Sub.batch[Mouse.moves DragAt,Mouse.ups DragEnd]
--看法
(=>) = (,)
查看:模型->Html消息
视图模型=
分区[]
Int->String->Html消息
itemView模型索引项=
让
锌试剂=
案例模型
只是{id}->
如果index==id,那么
"99"
其他的
"0"
没有->
"0"
在里面
div
[onMouseDown索引
风格
[“背景色”=>“#3C8D2F”
,“边框”=>“2倍纯色橙色”
,“光标”=>“移动”
,“位置”=>“相对”
,“transform”=>(getOffset模型索引)
,“z指数”=>zIndex
,“宽度”=>“100px”
,“高度”=>“100px”
,“边界半径”=>“4px”
,“颜色”=>“白色”
,“显示”=>“弹性”
,“对齐项目”=>“居中”
,“对齐内容”=>“中心”
,“用户选择”=>“无”
]
]
[文本项目
]
px:Int->String
px数=
toString编号+++“px”
getOffset:Model->Int->String
getOffset{位置,项,拖动}索引=
案例拖动
没有->
翻译0
只需{id,start,current}->
如果index==id,那么
翻译(current.x-start.x)(current.y-start.y)
其他的
翻译0
翻译:Int->Int->String
平移x y=
翻译(“++toString x++”px,++toString y++”px)
onMouseDown:Int->attributemsg
onMouseDown id=
在“mousedown”(Json.map(DragStart id)Mouse.po上